sqlite3使用简介
下载地址: http://www.sqlite.org/download.html
一.使用流程
要使用sqlite,需要从sqlite官网下载到三个文件,分别为sqlite3.lib,sqlite3.dll,sqlite3.h,然后再在自己的工程中配置好头文件和库文件,同时将dll文件放到当前目录下,就完成配置可以使用sqlite了。
使用的过程根据使用的函数大致分为如下几个过程:
- sqlite3_open()
- sqlite3_prepare()
- sqlite3_step()
- sqlite3_column()
- sqlite3_finalize()
- sqlite3_close()
这几个过程是概念上的说法,而不完全是程序运行的过程,如sqlite3_column()表示的是对查询获得一行里面的数据的列的各个操作统称,实际上在sqlite中并不存在这个函数。
1. sqlite3_open():打开数据库
在操作数据库之前,首先要打开数据库。这个函数打开一个sqlite数据库文件的连接并且返回一个数据库连接对象。这个操作同时程序中的第一个调用的sqlite函数,同时也是其他sqlite api的先决条件。许多的sqlite接口函数都需要一个数据库连接对象的指针作为它们的第一个参数。
函数定义
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
int sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */
);
说明:
假如这个要被打开的数据文件不存在,则一个同名的数据库文件将被创建。如果使用sqlite3_open和sqlite3_open_v2的话,数据库将采用UTF-8的编码方式,sqlite3_open16采用UTF-16的编码方式
返回值:
如果sqlite数据库被成功打开(或创建),将会返回SQLITE_OK,否则将会返回错误码。Sqlite3_errmsg()或者sqlite3_errmsg16可以用于获得数据库打开错误码的英文描述,这两个函数定义为:
const char *sqlite3_errmsg(sqlite3*);
const void *sqlite3_errmsg16(sqlite3*);
参数说明:
filename:需要被打开的数据库文件的文件名,在sqlite3_open和sqlite3_open_v2中这个参数采用UTF-8编码,而在sqlite3_open16中则采用UTF-16编码
ppDb:一个数据库连接句柄被返回到这个参数,即使发生错误。唯一的一场是如果sqlite不能分配内存来存放sqlite对象,ppDb将会被返回一个NULL值。
flags:作为数据库连接的额外控制的参数,可以是SQLITE_OPEN_READONLY,SQLITE_OPEN_READWRITE和SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE中的一个,用于控制数据库的打开方式,可以和SQLITE_OPEN_NOMUTEX,SQLITE_OPEN_FULLMUTEX, SQLITE_OPEN_SHAREDCACHE,以及SQLITE_OPEN_PRIVATECACHE结合使用,具体的详细情况可以查阅文档
2. Sqlite3_prepare()
这个函数将sql文本转换成一个准备语句(prepared statement)对象,同时返回这个对象的指针。这个接口需要一个数据库连接指针以及一个要准备的包含SQL语句的文本。它实际上并不执行(evaluate)这个SQL语句,它仅仅为执行准备这个sql语句
函数定义(仅列出UTF-8的)
int sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
参数:
db:数据指针
zSql:sql语句,使用UTF-8编码
nByte:如果nByte小于0,则函数取出zSql中从开始到第一个0终止符的内容;如果nByte不是负的,那么它就是这个函数能从zSql中读取的字节数的最大值。如果nBytes非负,zSql在第一次遇见’/000/或’u000’的时候终止
pzTail:上面提到zSql在遇见终止符或者是达到设定的nByte之后结束,假如zSql还有剩余的内容,那么这些剩余的内容被存放到pZTail中,不包括终止符
ppStmt:能够使用sqlite3_step()执行的编译好的准备语句的指针,如果错误发生,它被置为NULL,如假如输入的文本不包括sql语句。调用过程必须负责在编译好的sql语句完成使用后使用sqlite3_finalize()删除它。
说明
如果执行成功,则返回SQLITE_OK,否则返回一个错误码。推荐在现在任何的程序中都使用sqlite3_prepare_v2这个函数,sqlite3_prepare只是用于前向兼容
备注
<1>准备语句(prepared statement)对象
typedef struct sqlite3_stmt sqlite3_stmt;
准备语句(prepared statement)对象一个代表一个简单SQL语句对象的实例,这个对象通常被称为“准备语句”或者“编译好的SQL语句”或者就直接称为“语句”。
语句对象的生命周期经历这样的过程:
l 使用sqlite3_prepare_v2或相关的函数创建这个对象
l 使用sqlite3_bind_*()给宿主参数(host parameters)绑定值
l 通过调用sqlite3_step一次或多次来执行这个sql
l 使用sqlite3——reset()重置这个语句,然后回到第2步,这个过程做0次或多次
l 使用sqlite3_finalize()销毁这个对象
在sqlite中并没有定义sqlite3_stmt这个结构的具体内容,它只是一个抽象类型,在使用过程中一般以它的指针进行操作,而sqlite3_stmt类型的指针在实际上是一个指向Vdbe的结构体得指针
<2>宿主参数(host parameters)
在传给sqlite3_prepare_v2()的sql的语句文本或者它的变量中,满足如下模板的文字将被替换成一个参数:
l ?
l ?NNN,NNN代表数字
l :VVV,VVV代表字符
l @VVV
l $VVV
在上面这些模板中,NNN代表一个数字,VVV代表一个字母数字标记符(例如:222表示名称为222的标记符),sql语句中的参数(变量)通过上面的几个模板来指定,如
“select ? from ? “这个语句中指定了两个参数,sqlite语句中的第一个参数的索引值是1,这就知道这个语句中的两个参数的索引分别为1和2,使用”?”的话会被自动给予索引值,而使用”?NNN”则可以自己指定参数的索引值,它表示这个参数的索引值为NNN。”:VVV”表示一个名为”VVV”的参数,它也有一个索引值,被自动指定。
可以使用sqlite3_bind_*()来给这些参数绑定值
3. sqlite3_setp()
这个过程用于执行有前面sqlite3_prepare创建的准备语句。这个语句执行到结果的第一行可用的位置。继续前进到结果的第二行的话,只需再次调用sqlite3_setp()。继续调用sqlite3_setp()知道这个语句完成,那些不返回结果的语句(如:INSERT,UPDATE,或DELETE),sqlite3_step()只执行一次就返回
函数定义
int sqlite3_step(sqlite3_stmt*);
返回值
函数的返回值基于创建sqlite3_stmt参数所使用的函数,假如是使用老版本的接口sqlite3_prepare()和sqlite3_prepare16(),返回值会是 SQLITE_BUSY, SQLITE_DONE, SQLITE_ROW, SQLITE_ERROR 或 SQLITE_MISUSE,而v2版本的接口sqlite3_prepare_v2()和sqlite3_prepare16_v2()则会同时返回这些结果码和扩展结果码。
对所有V3.6.23.1以及其前面的所有版本,需要在sqlite3_step()之后调用sqlite3_reset(),在后续的sqlite3_ step之前。如果调用sqlite3_reset重置准备语句失败,将会导致sqlite3_ step返回SQLITE_MISUSE,但是在V3. 6.23.1以后,sqlite3_step()将会自动调用sqlite3_reset。
int sqlite3_reset(sqlite3_stmt *pStmt);
sqlite3_reset用于重置一个准备语句对象到它的初始状态,然后准备被重新执行。所有sql语句变量使用sqlite3_bind*绑定值,使用sqlite3_clear_bindings重设这些绑定。Sqlite3_reset接口重置准备语句到它代码开始的时候。sqlite3_reset并不改变在准备语句上的任何绑定值,那么这里猜测,可能是语句在被执行的过程中发生了其他的改变,然后这个语句将它重置到绑定值的时候的那个状态。
4. sqlite3_column()
这个过程从执行sqlite3_step()执行一个准备语句得到的结果集的当前行中返回一个列。每次sqlite3_step得到一个结果集的列停下后,这个过程就可以被多次调用去查询这个行的各列的值。对列操作是有多个函数,均以sqlite3_column为前缀
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
说明
第一个参数为从sqlite3_prepare返回来的prepared statement对象的指针,第二参数指定这一行中的想要被返回的列的索引。最左边的一列的索引号是0,行的列数可以使用sqlite3_colum_count()获得。
这些过程会根据情况去转换数值的类型,sqlite内部使用sqlite3_snprintf()去自动进行这个转换,下面是关于转换的细节表:
内部类型 | 请求的类型 | 转换 |
NULL | INTEGER | 结果是0 |
NULL | FLOAT | 结果是0.0 |
NULL | TEXT | 结果是NULL |
NULL | BLOB | 结果是NULL |
INTEGER | FLOAT | 从整形转换到浮点型 |
INTEGER | TEXT | 整形的ASCII码显示 |
INTEGER | BLOB | 同上 |
FLOAT | INTEGER | 浮点型转换到整形 |
FLOAT | TEXT | 浮点型的ASCII显示 |
FLOAT | BLOB | 同上 |
TEXT | INTEGER | 使用atoi() |
TEXT | FLOAT | 使用atof() |
TEXT | BLOB | 没有转换 |
BLOB | INTEGER | 先到TEXT,然后使用atoi |
BLOB | FLOAT | 先到TEXT,然后使用atof |
BLOB | TEXT | 如果需要的话添加0终止符 |
注:BLOB数据类型是指二进制的数据块,比如要在数据库中存放一张图片,这张图片就会以二进制形式存放,在sqlite中对应的数据类型就是BLOB
int sqlite3_column_bytes(sqlite3_stmt*, int iCol)int sqlite3_column_bytes16(sqlite3_stmt*, int iCol)两个函数返回对应列的内容的字节数,这个字节数不包括后面类型转换过程中加上的0终止符。
下面是几个最安全和最简单的使用策略
- 先sqlite3_column_text() ,然后 sqlite3_column_bytes()
- 先sqlite3_column_blob(),然后sqlite3_column_bytes()
- 先sqlite3_column_text16(),然后sqlite3_column_bytes16()
5. sqlite3_finalize
int sqlite3_finalize(sqlite3_stmt *pStmt);
这个过程销毁前面被sqlite3_prepare创建的准备语句,每个准备语句都必须使用这个函数去销毁以防止内存泄露。
在空指针上调用这个函数没有什么影响,同时可以准备语句的生命周期的任一时刻调用这个函数:在语句被执行前,一次或多次调用sqlite_reset之后,或者在sqlite3_step任何调用之后不管语句是否完成执行
6. sqlite3_close
这个过程关闭前面使用sqlite3_open打开的数据库连接,任何与这个连接相关的准备语句必须在调用这个关闭函数之前被释放
二.使用举例
?
|
输出的结果:
ID = 1
UserName = kfqcome
PassWord = 123456
ID = 2
UserName = miss wang
PassWord = 654321
这里执行sql语句用的是sqlite3_exec,它是前面几个函数的封装
int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
sqlite3_exec是sqlite3_prepare_v2,sqlite3_step()和sqlite3_finalize()的封装,能让程序多次执行sql语句而不要写许多重复的代码。
Sqlite3_exec接口执行0或多个UTF-8编码的,分号分割的sql语句,传到第二个参数中。如果sqlite3_exec的第三个参数回调函数指针不为空,那么它会为每个来自执行的SQL语句的结果行调用(也就是说回调函数会调用多次,上面例子中会返回2个结果行,因而会被执行2次),第4个参数是传给回调函数的第一个参数,如果回调函数指针为空,那么回调不会发生同时结果行被忽略。
如果在执行sql语句中有错误发生,那么当前的语句的执行被停止,后续的语句也被跳过。第五个参数不为空的时候,它被分配内存并写入了错误信息,所以在sqlite3_exec后面需要调用sqlite3_free去释放这个对象以防止内存泄露
回调函数:
int (*callback)(void*,int,char**,char**), /* Callback function */
第一个参数通过sqlite3_exec的第第四个参数传入的
第二个参数是结果行的列数
第三个参数是行中列数据的指针
第四个参数是行中列名称的指针
一.建立数据库
sqlite3.exe test.db
二.双击sqlite-3_6_16目录下的程序sqlite3.exe,即可运行
三.退出
.exit
或者
.quit
四.SQLite支持如下5种数据类型
1.NULL:空值。
2.INTEGER:带符号的整型,具体取决有存入数字的范围大小。
3.REAL:浮点数字,存储为8-byte IEEE浮点数。
4.TEXT:字符串文本。
5.BLOB:二进制对象。
五.联系人表格结构如下
create table contact(id integer primary key autoincrement,
lastname varchar(20),firstname varchar(20),
mobile varchar(30), telephone varchar(20),
email varchar(30), company varchar(50),
department varchar(16),address varchar(80),
id1 interger,id2 integer, updatetime datetime);
六.查看数据库有哪些数据表
命令是:.tables
七.如何插入一条记录
insert into contact(lastname,firstname,mobile,telephone,updatetime) values('刘','畅','13910128132','010-81749136','2009-07-22');
八.查看数据表的结构
针对整个数据库
.schema
针对仅仅是contact联系人该表
.schema contact 注意没有分号
九.如何打开一个已经创建的数据库
sqlite3 test.db
十.如何解决如下问题
SQL error: near "sqlite3": syntax error
SQL指令都是以分号(;)结尾的。如果遇到两个减号(--)则代表注解,sqlite3会略过去
十一.如何建立索引
create index index_name on table_name(field_to_be_indexed);
十二.如何删除一张数据表
drop table contact;
十三.查看当前的数据库
.database
十四.如何删除一个数据表的数据
delete from contact;
十五.如何导入一个文件到某个表中
.import 文件路径 表名
注意这是非SQL语句,所以不加分号
十六.如何设置文件字段的分隔符
.separator “,”
.import e:/contact.txt contact
十七.如何查看当前sqllite字段的分隔符是什么?
.show
十八.如何将查询结果导出到一个文件
第一步:.output a.txt
第二步:执行要导出的SQL语句
第三步:.output stdout
十九.SQL查询语句
select * from film order by year limit 10;
select * from film order by year desc limit 10;
select count(*) from film;
select * from film where starring like 'Jodie%';
select * from film where starring='Jodie Foster';
select title, year from film order by year desc limit 10;
select columns from table_name where expression;
最常见的用法,当然是倒出所有数据库的内容:
select * from film;
如果资料太多了,我们或许会想限制笔数:
select * from film limit 10;
或是照着电影年份来排列:
select * from film order by year limit 10;
或是年份比较近的电影先列出来:
select * from film order by year desc limit 10;
或是我们只想看电影名称跟年份:
select title, year from film order by year desc limit 10;
查所有茱蒂佛斯特演过的电影:
select * from film where starring='Jodie Foster';
查所有演员名字开头叫茱蒂的电影('%' 符号便是 SQL 的万用字符):
select * from film where starring like 'Jodie%';
查所有演员名字以茱蒂开头、年份晚于1985年、年份晚的优先列出、最多十笔,只列出电影名称和年份:
select title, year from film where starring like 'Jodie%' and year >= 1985 order by year desc limit 10;
有时候我们只想知道数据库一共有多少笔资料:
select count(*) from film;
有时候我们只想知道1985年以后的电影有几部:
select count(*) from film where year >= 1985;
(进一步的各种组合,要去看SQL专书,不过你大概已经知道SQL为什么这么流行了:这种语言允许你将各种查询条件组合在一起──而我们还没提到「跨数据库的联合查询」呢!)
如何更改或删除资料
了解select的用法非常重要,因为要在sqlite更改或删除一笔资料,也是靠同样的语法。
例如有一笔资料的名字打错了:
update film set starring='Jodie Foster' where starring='Jodee Foster';
就会把主角字段里,被打成'Jodee Foster'的那笔(或多笔)资料,改回成Jodie Foster。
delete from film where year < 1970;
就会删除所有年代早于1970年(不含)的电影了。
其他sqlite的特别用法
sqlite可以在shell底下直接执行命令:
sqlite3 film.db "select * from film;"
输出 HTML 表格:
sqlite3 -html film.db "select * from film;"
将数据库「倒出来」:
sqlite3 film.db ".dump" > output.sql
利用输出的资料,建立一个一模一样的数据库(加上以上指令,就是标准的SQL数据库备份了):
sqlite3 film.db < output.sql
在大量插入资料时,你可能会需要先打这个指令:
begin;
插入完资料后要记得打这个指令,资料才会写进数据库中:
commit;
创建数据库文件:
>SQLite3 d:/test.db 回车
就生成了一个test.db在d盘。
这样同时也SQLite3挂上了这个test.db
2)
用.help可以看看有什么命令
>.help 回车即可
3)可以在这里直接输入SQL语句创建表格 用;结束 ,然后回车就可以看到了
4)看看有创建了多少表
>.tables
5)看表结构
>.schema 表名
6)看看目前的数据库
>.database
7)如果要把查询输出到文件
>.output 文件名
> 查询语句;
查询结果就输出到了文件c:/query.txt
把查询结果用屏幕输出
>.output stdout
8)把表结构输出,同时索引也会输出
.dump 表名
9)退出
>.exit 或者.quit
2。从http://sqlite.phxsoftware.com/ 下载Ado.net驱动。
下载了安装,在安装目录中存在System.Data.SQLite.dll
我们只需要拷贝这个文件到引用目录,并添加引用即可对SQLite数据库操作了
所有的Ado.net对象都是以SQLite开头的,比如SQLiteConnection
连接串只需要如下方式
Data Source=d:/test.db 或者DataSource=test.db--应用在和应用程序或者.net能够自动找到的目录
剩下的就很简单了~~
SQL语法
由于以前用SQLServer或者ISeries,所以DDL的语法很汗颜
1)创建一个单个Primary Key的table
CREATE TABLE [Admin] (
[UserName] [nvarchar] (20) PRIMARY KEY NOT NULL ,
[Password] [nvarchar] (50) NOT NULL ,
[Rank] [smallint] NOT NULL ,
[MailServer] [nvarchar] (50) NOT NULL ,
[MailUser] [nvarchar] (50) NOT NULL ,
[MailPassword] [nvarchar] (50) NOT NULL ,
[Mail] [nvarchar] (50) NOT NULL
) ;
2)创建一个多个Primary Key的table
CREATE TABLE [CodeDetail] (
[CdType] [nvarchar] (10) NOT NULL ,
[CdCode] [nvarchar] (20) NOT NULL ,
[CdString1] [ntext] NOT NULL ,
[CdString2] [ntext] NOT NULL ,
[CdString3] [ntext] NOT NULL,
PRIMARY KEY (CdType,CdCode)
) ;
3)创建索引
CREATE INDEX [IX_Account] ON [Account]([IsCheck], [UserName]);
还可以视图等等。
4.还有很有用的SQL
Select * from Sqlite_master
Select datetime('now')
Select date('now')
Select time('now')
SQLite 内建函数表
算术函数 | |
abs(X) | 返回给定数字表达式的绝对值。 |
max(X,Y[,...]) | 返回表达式的最大值。 |
min(X,Y[,...]) | 返回表达式的最小值。 |
random(*) | 返回随机数。 |
round(X[,Y]) | 返回数字表达式并四舍五入为指定的长度或精度。 |
字符处理函数 | |
length(X) | 返回给定字符串表达式的字符个数。 |
lower(X) | 将大写字符数据转换为小写字符数据后返回字符表达式。 |
upper(X) | 返回将小写字符数据转换为大写的字符表达式。 |
substr(X,Y,Z) | 返回表达式的一部分。 |
randstr() |
|
quote(A) |
|
like(A,B) | 确定给定的字符串是否与指定的模式匹配。 |
glob(A,B) |
|
条件判断函数 | |
coalesce(X,Y[,...]) |
|
ifnull(X,Y) |
|
nullif(X,Y) |
|
集合函数 | |
avg(X) | 返回组中值的平均值。 |
count(X) | 返回组中项目的数量。 |
max(X) | 返回组中值的最大值。 |
min(X) | 返回组中值的最小值。 |
sum(X) | 返回表达式中所有值的和。 |
其他函数 | |
typeof(X) | 返回数据的类型。 |
last_insert_rowid() | 返回最后插入的数据的 ID 。 |
sqlite_version(*) | 返回 SQLite 的版本。 |
change_count() | 返回受上一语句影响的行数。 |
last_statement_change_count() |
|
oh,还有就是看到有人说,好像成批插入的时候,启动事务,比不启动事务快n倍
还有就是尽量使用参数化的SQL,估计和商用DB一样能够自动Prepare.
===========
sqlite可以在shell/dos command底下直接执行命令:
sqlite3 film.db "select * from film;"
输出 HTML 表格:
sqlite3 -html film.db "select * from film;"
将数据库「倒出来」:
sqlite3 film.db ".dump" > output.sql
利用输出的资料,建立一个一模一样的数据库(加上以上指令,就是标准的SQL数据库备份了):
sqlite3 film.db < output.sql
在大量插入资料时,你可能会需要先打这个指令:
begin;
插入完资料后要记得打这个指令,资料才会写进数据库中:
commit;
SQLITE深入------常见问题
如何建立自动增长字段?
声明为 INTEGER PRIMARY KEY 的列将会自动增长
长一点的答案: 如果你声明表的一列为 INTEGER PRIMARY KEY,那么, 每当你在该列上插入一NULL值时, NULL自动被转换为一个比该列中最大值大1的一个整数,如果表是空的, 将会是1。 (如果是最大可能的主键9223372036854775807,那个,将键值将是随机未使用的数。) 如,有下列表:
CREATE TABLE t1(
a INTEGER PRIMARY KEY,
b INTEGER
);
在该表上,下列语句
INSERT INTO t1 VALUES(NULL,123);
在逻辑上等价于:
INSERT INTO t1 VALUES((SELECT max(a) FROM t1)+1,123);
有一个新的API叫做 sqlite3_last_insert_rowid(), 它将返回最近插入的整数值。 注意该整数会比表中该列上的插入之前的最大值大1。 该键值在当前的表中是唯一的。但有可能与已从表中删除的值重叠。要想建立在整个表的生命周期中唯一的键值,需要在 INTEGER PRIMARY KEY 上增加AUTOINCREMENT声明。那么,新的键值将会比该表中曾能存在过的最大值大1。如果最大可能的整数值在数据表中曾经存在过,INSERT将会失败, 并返回SQLITE_FULL错误代码。
多个应用程序或一个应用程序的多个实例可以同时访问同一个数据库文件吗?
多个进程可同时打开同一个数据库。多个进程可以同时进行SELECT 操作,但在任一时刻,只能有一个进程对数据库进行更改。
SQLite使用读、写锁控制对数据库的访问。(在Win95/98/ME等不支持读、写锁的系统下,使用一个概率性的模拟来代替。)但使用时要注意: 如果数据库文件存放于一个NFS文件系统上,这种锁机制可能不能正常工作。 这是因为fcntl() 文件锁在很多NFS上没有正确的实现。 在可能有多个进程同时访问数据库的时候,应该避免将数据库文件放到NFS上。在Windows上,Microsoft的文档中说:如果使用 FAT 文件系统而没有运行 share.exe 守护进程,那么锁可能是不能正常使用的。那些在Windows上有很多经验的人告诉我:对于网络文件,文件锁的实现有好多Bug,是靠不住的。如果他们说的是对的,那么在两台或多台Windows机器间共享数据库可能会引起不期望的问题。
我们意识到,没有其它嵌入式的 SQL 数据库引擎能象 SQLite 这样处理如此多的并发。SQLite允许多个进程同时打开一个数据库,同时读一个数据库。当有任何进程想要写时,它必须在更新过程中锁住数据库文件。但那通常只是几毫秒的时间。其它进程只需等待写进程干完活结束。典型地,其它嵌入式的SQL数据库引擎同时只允许一个进程连接到数据库。
但是,Client/Server数据库引擎(如 PostgreSQL, MySQL, 或 Oracle)通常支持更高级别的并发,并且允许多个进程同时写同一个数据库。这种机制在Client/Server结构的数据库上是可能的,因为总是有一个单一的服务器进程很好地控制、协调对数据库的访问。如果你的应用程序需要很多的并发,那么你应该考虑使用一个Client/Server 结构的数据库。但经验表明,很多应用程序需要的并发,往往比其设计者所想象的少得多。
当SQLite试图访问一个被其它进程锁住的文件时,缺省的行为是返回 SQLITE_BUSY。 可以在C代码中使用sqlite3_busy_handler() 或 sqlite3_busy_timeout() API 函数调整这一行为。
在SQLite数据库中如何列出所有的表和索引?
如果你运行 sqlite3 命令行来访问你的数据库,可以键入 “.tables”来获得所有表的列表。或者,你可以输入“.schema” 来看整个数据库模式,包括所有的表的索引。输入这些命令,后面跟一个LIKE模式匹配可以限制显示的表。
在一个 C/C++ 程序中(或者脚本语言使用 Tcl/Ruby/Perl/Python 等) 你可以在一个特殊的名叫 SQLITE_MASTER 上执行一个SELECT查询以获得所有 表的索引。每一个 SQLite 数据库都有一个叫 SQLITE_MASTER 的表, 它定义数据库的模式。 SQLITE_MASTER 表看起来如下:
CREATE TABLE sqlite_master (
type TEXT,
name TEXT,
tbl_name TEXT,
rootpage INTEGER,
sql TEXT
);
对于表来说,type 字段永远是 'table',name 字段永远是表的名字。所以,要获得数据库中所有表的列表,使用下列SELECT语句:
SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;
对于索引,type 等于 'index', name 则是索引的名字,tbl_name 是该索引所属的表的名字。不管是表还是索引,sql字段是原先用 CREATE TABLE 或 CREATE INDEX 语句创建它们时的命令文本。对于自动创建的索引(用来实现 PRIMARY KEY 或 UNIQUE 约束),sql字段为NULL。
SQLITE_MASTER 表是只读的。不能对它使用 UPDATE、INSERT 或 DELETE。 它会被 CREATE TABLE、CREATE INDEX、DROP TABLE 和 DROP INDEX 命令自动更新。
临时表不会出现在 SQLITE_MASTER 表中。临时表及其索引和触发器存放在另外一个叫 SQLITE_TEMP_MASTER 的表中。SQLITE_TEMP_MASTER 跟 SQLITE_MASTER 差不多,但它只是对于创建那些临时表的应用可见。如果要获得所有表的列表, 不管是永久的还是临时的,可以使用类似下面的命令:
SELECT name FROM
(SELECT * FROM sqlite_master UNION ALL
SELECT * FROM sqlite_temp_master)
WHERE type='table'
ORDER BY name
在SQLite中,VARCHAR字段最长是多少?
SQLite 不强制 VARCHAR 的长度。 你可以在 SQLITE 中声明一个 VARCHAR(10),SQLite还是可以很高兴地允许你放入500个字符。 并且这500个字符是原封不动的,它永远不会被截断。
SQLite支持二进制大对象吗?
SQLite 3.0 及以后版本允许你在任何列中存储 BLOB 数据。 即使该列被声明为其它类型也可以。
在SQLite中,如何在一个表上添加或删除一列?
SQLite 有有限地 ALTER TABLE 支持。你可以使用它来在表的末尾增加一列,可更改表的名称。 如果需要对表结构做更复杂的改变,则必须重新建表。重建时可以先将已存在的数据放到一个临时表中,删除原表, 创建新表,然后将数据从临时表中复制回来。
如,假设有一个 t1 表,其中有 "a", "b", "c" 三列, 如果要删除列 c ,以下过程描述如何做:
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,b);
INSERT INTO t1_backup SELECT a,b FROM t1;
DROP TABLE t1;
CREATE TABLE t1(a,b);
INSERT INTO t1 SELECT a,b FROM t1_backup;
DROP TABLE t1_backup;
COMMIT;
在数据库中删除了很多数据,但数据库文件没有变小,是Bug吗?
不是。当你从SQLite数据库中删除数据时, 未用的磁盘空间将会加入一个内部的“自由列表”中。 当你下次插入数据时,这部分空间可以重用。磁盘空间不会丢失,但也不会返还给操作系统。
如果删除了大量数据,而又想缩小数据库文件占用的空间,执行 VACUUM 命令。 VACUUM 将会从头重新组织数据库。这将会使用数据库有一个空的“自由链表”, 数据库文件也会最小。但要注意的是,VACUUM 的执行会需要一些时间(在SQLite开发时,在Linux上,大约每M字节需要半秒种),并且, 执行过程中需要原数据库文件至多两倍的临时磁盘空间。
对于 SQLite 3.1版本,一个 auto-vacumm 模式可以替代 VACUUM 命令。 可以使用 auto_vacuum pragma 打开。
SQLITE_SCHEMA error是什么错误?为什么会出现该错误?
当一个准备好的(prepared)SQL语句不再有效或者无法执行时, 将返回一个 SQLITE_SCHEMA 错误。发生该错误时,SQL语句必须使用 sqlite3_prepare() API来重新编译. 在 SQLite 3 中, 一个 SQLITE_SCHEMA 错误只会发生在用 sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API 执行 SQL 时。而不会发生在使用sqlite3_exec()时。 在版本2中不是这样。
准备好的语句失效的最通常原因是:在语句准备好后, 数据库的模式又被修改了。另外的原因会发生在:
数据库离线:DETACHed.
数据库被 VACUUMed
一个用户存储过程定义被删除或改变。
一个 collation 序列定义被删除或改变。
认证函数被改变。
在所有情况下,解决方法是重新编译并执行该SQL语句。 因为一个已准备好的语句可以由于其它进程改变数据库模式而失效,所有使用 sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API 的代码都应准备处理 SQLITE_SCHEMA错误。下面给出一个例子:
int rc;
sqlite3_stmt *pStmt;
char zSql[] = "SELECT .....";
do {
/* Compile the statement from SQL. Assume success. */
sqlite3_prepare(pDb, zSql, -1, &pStmt, 0);
while( SQLITE_ROW==sqlite3_step(pStmt) ){
/* Do something with the row of available data */
}
/* Finalize the statement. If an SQLITE_SCHEMA error has
** occured, then the above call to sqlite3_step() will have
** returned SQLITE_ERROR. sqlite3_finalize() will return
** SQLITE_SCHEMA. In this case the loop will execute again.
*/
rc = sqlite3_finalize(pStmt);
} while( rc==SQLITE_SCHEMA );
如何在字符串中使用单引号(')?
SQL 标准规定,在字符串中,单引号需要使用逃逸字符,即在一行中使用两个单引号。在这方面 SQL 用起来类似Pascal 语言。 SQLite 尊循标准。如:
INSERT INTO xyz VALUES('5 O''clock');
Sqlite中如何返回本地化当前时间?
在做ClinicOS的时候遇到一个问题,在保存病历登记时间时,我使用了“CURRENT_TIMESTAMP”,但这有个问题,它返回的是UTC Time,这对我们中国人没啥用,一直希望能想办法将它转为localtime。今天刚好有空,所以去查了查Sqlite的Mail List,果然也有人遇到了这个问题,我从一篇名为《translate time comparison statement》(http://www.mail-archive.com/sqlite-users@sqlite.org /msg12350.html)中看到这样的回复:
二十.如何更新表中数据
update contact set lastname=’江南七怪’where id = 1028
update contact set lastname='江南七怪', mobile='13912345678' where id=1028;
二十一.如何一次插入多个数据
Insert into SAMPLE(PRJNUM, PRJNAME, EMYNUM, EMYNAME, SALCATEGORY, SALPACKAGE)
values(100001, 'TPMS', 200001, 'Johnson', 'A', 2000), (100001, 'TPMS', 200002,
'Christine', 'B', 3000), (100001, 'TPMS', 200003, 'Kevin', 'C', 4000), (100002,
'TCT', 200001, 'Johnson', 'A', 2000), (100002, 'TCT', 200004, 'Apple', 'B',
3000);