SQLite是一个非常轻量级自包含(lightweight and self-contained)的DBMS,它可移植性好,很容易使用,很小,高效而且可靠。SQLite嵌入到使用它的应用程序中,它们共用相同的进程空间,而不是单独的一个进程。从外部看,它并不像一个RDBMS,但在进程内部,它却是完整的,自包含的数据库引擎。
嵌入式数据库的一大好处就是在你的程序内部不需要网络配置,也不需要管理。因为客户端和服务器在同一进程空间运行。SQLite 的数据库权限只依赖于文件系统,没有用户帐户的概念。SQLite 有数据库级锁定,没有网络服务器。它需要的内存,其它开销很小,适合用于嵌入式设备。你需要做的仅仅是把它正确的编译到你的程序。
下面将介绍SQLite的使用:
一、创建SQLite数据库
1、手工创建
使用sqlite3 工具,通过手工输入SQL命令完成数据库创建,用户在Linux 的命令行界面中输入 sqlite3 可启动 sqlite3工具。
2、代码创建
在代码中动态创建数据库。
在程序执行过程中,当需要进行数据库操作时,应用程序会首先尝试打开数据库,此时如果数据库并不存在,程序会自动建立数据库,然后打开数据库。
二、SQLite常用命令介绍
1、sqlite3 指令(通常以 . 开头)
1)创建或打开一个数据库文件
在终端下运行 sqlite3 < *.db > 指令:

<*.db> 是要打开的数据库文件。若该文件不存在,则自动创建。
2)显示当前打开的数据库文件
sqlite > .database

可以看到当前打开的数据库文件正是刚刚建立的 test.db文件;
3)显示数据库中所有表名
sqlite > .tables

可以看到当前用户下有一个名为 stu 的表;
4)查看表的结构
sqlite > .schema <table_name>

其实这里显示的正是我们创建新表时输入的命令;
5)显示所有命令
sqlite > .help

6) 退出 sqlite3
sqlite > .quit

7) 修改 .header和 .mode
sqlite>.header on
sqlite>.mode column

2、SQL命令
每个命令以 ;结束
1)创建新表
sqlite > create table <table_name> (f1 type1, f2 type2,...);

type为数据类型:
NULL 标识一个NULL值
INTERGER 整数类型int
REAL 浮点型,float,doubale
TEXT 字符串
CHAR 字符型
BLOB 二进制010101
注意:若未指定类型,默认是字符串,向表中添加新纪录时要加 " ";
2)删除表
sqlite > drop table <table_name>;

可以看到原来有两个表 stu与stu2 ,使用 drop table stu2 后可以看到 只剩下 stu;
3)向表中添加新纪录
sqlite >insert into <table_name> <(f1, f2, f3)> values(value1,value2,...);

或 (id, name, score)可省略不写

可以看到最新的记录被添加进去;
4)查询表中所有记录
sqlite >select * from <table_name>;

5)按指定条件查询表中记录
sqlite >select * from <table_name> where <expression>;

这里的条件是 score >90 ,可以看到 score > 90 的数据被挑选出来;

这里的条件是 score >90 and score <95,可以看到 score >90 and score <95 的数据被挑选出来;

6)查询student表中指定的字段
select name, id from stduent;

7)限制输出数据记录数量
select * from table_name limit val;

8)升序输出数据记录
select * from table_name order by f1 asc;

9)降序输出数据记录
select * from table_name order by f1 desc;

10)按指定的条件删除表中记录
sqlite >delete from <table_name> where <expression>;

可以看到 id=1003 的被删除;
不加判断条件则清空所有数据记录
11) 更新表中记录
sqlite > updata <table_name> set <f1=value1>,<f2=value2>... where <expression>;

可以看到 id=1003 的数据被更新。
再次提醒,未定义类型的记录默认是字符串,添加时一定要用 " " ;
12)在表中添加字段
sqlite > alter table <table> add column <field><type> defalut... ;

可以看到 sex 被添加进去;
13)删除指定字段(列)
step1: alter table info rename to temp; //备份为temp
step2: create table info (id, name, age); //创建新表
step3: inset into info select id, name, age from temp; //导出到新表

14)数据库备份
在命令提示符中使用.dump命令来导出完整的数据库在一个文本文件中,如图所示
sqlite3 test.db .dump > testDB.sql
上面命令将转换整个test.db数据库的内容到SQLite的语句中,并将其转储到ASCII文本文件中testDB.sql中。可以通过简单的方式从生成的testDB.sql恢复。
sqlite3 test.db < testDB.sql

三、SQLite 编程接口
1、打开sqlite 数据库 sqlite3_open
函数原型:
int sqlite3_open(
const char *fileName,
sqlite3 **ppDB
);
函数功能:打开一个数据库;若该数据库文件不存在,则自动创建。打开或者创建数据库的命令会被缓存,直到这个数据库真正被调用的时候才会被执行。
输入参数:fileName,待打开的数据库文件名称,包括路径,以’\0’结尾;特别说明:SQLite支持内存数据库,内存方式存储使用文件名“:memory:”
输出参数:ppDB,返回打开的数据库句柄;
返回值:执行成功返回SQLITE_OK,否则返回其他值;
2、关闭 sqlite 数据库sqlite3_close
函数原型:
int sqlite3_close(sqlite3 *pDB);
函数功能:关闭一个打开的数据库;
输入参数:pDB,打开的数据库句柄
输出参数:无
返回值:执行成功返回SQLITE_OK,否则返回其他值
3、sqlite3_errmsg
函数原型:
const char *sqlite3_errmsg(sqlite3 *pDB);
函数功能:获取最近调用的API接口返回的错误说明,这些错误信息UTF-8的编码返回,并且在下一次调用任何SQLiteAPI函数时被自动清除;
输入参数:pDB,打开的数据库句柄
输出参数:无
返回值:错误说明的字符串指针
4、sqlite3_exec
函数原型:
int sqlite3_exec(
sqlite3 *pDB,
const char *sql,
int (*callback)(void*, int, char**, char**),
void *para,
char **errMsg
);
函数功能:编译和执行零个或多个SQL语句,查询的结果返回给回调函数callback
输入参数:
pDB, 数据库句柄;
sql,待执行的SQL语句字符串,以’\0’结尾;
callback, 回调函数,用来处理查询结果,
如果不需要回调(比如做insert或者delete操作时),可输入NULL;
para, 用户传入的参数,可以为NULL,该参数指针最终会被传给回调函数callback,
供用户在回调函数中使用, 是回掉函数的第一个参数;
输出参数:errMsg, 返回错误信息,注意是指针的指针。
返回值:执行成功返回SQLITE_OK,否则返回其他值。
5、回调函数sqlite_callback介绍
定义: 在一个函数里调用指定的另一个函数的方式(格式规定) 。
本质: 你想让别人的代码执行你的代码, 而别人的代码你又不能动。
函数格式:
int(*callback)(
void *para,
int columnCount,
char **columnValue,
char **columnName
);
函数功能:传给sqlite3_exec的回调函数,用来显示用户处理查询的结果。
对每一条查询结果调用一次该回调函数。
输入参数:
para sqlite3_exec传入的第四个参数指针
column_size 查询到的这条记录有多少字段(即表头的列数)。
column_value 查询出来的数据都保存在这里。实际上是一维数组(不是二维数组)
column_name 表示结果字段的名称。(与column_value是对应的)
输出参数:无
返回值:执行成功返回SQLITE_OK,否则返回其他值。
1 :中断查找
0 :继续列举查询到的数据 (SQLITE_OK)
【回掉函数特殊说明】
通常情况下,callback在select操作中会使用到,尤其是处理每行记录数。
返回的结果每一行记录都会调用下“回掉函数”。
如果回掉函数返回了非0,那么sqlite3_exec将返回SQLITE_ABORT,并且之后的回掉函数也不会执行,同时未执行的子查询也不会继续执行。
对于更新、删除、插入等不需要回掉函数的操作,sqlite3_exec的第三、第四个参数可以传入0或NULL。
【例】:
回调函数的格式如下:
int (*callback)(
void* pv, /* 由 sqlite3_exec() 的第四个参数传递而来 */
int argc, /* 表的列数 */
char** argv, /* 指向查询结果的指针数组 */
char** col /* 指向表头名的指针数组 */
);
示例表:
+-----------------------------------+
| id | pic | data(16进制数据) |
|-----------------------------------|
| 1 | a.jpg | 00 00 00 ... |
|-----------------------------------|
| 2 | b.jpg | XX XX XX |
+-----------------------------------+
对第一行数据:
argc=3 即 [0]...[2]
argv[0]="1", argv[1]="a.jpg", argv[2]="00 00 00..."(实际16进制数据,非这里显示的字符串形式)
col[0]="id", col[1]="pic", col[2]="data"
【说明】:
sqlite3_exec() 的回调函数必须按照此格式,当然形参的名字任意。
如果某列的数据类型不是char*, 则可以对结果执行相关的转换, 如:用atoi()把结果转换为整数(integer);
如果是二进制数据, 则可以直接强制类型转换, 如:(void*)argv[i] 。
该回调函数有两种返回值类型.
1. 返回零 : sqlite3_exec()将继续执行查询. (成功即返回SQLITE_OK)
2. 返回非零: sqlite3_exec()将立即中断查询, 且 sqlite3_exec() 将返回 SQLITE_ABORT。
【示例】:
int i;
for(i=0; i<argc; i++)
{
printf("%s\t%s\n\n", col[i], argv[i]);
}
下面是对数据库增删查改的简单实例练习 < sqlite3_IDSU.c >
#include <stdio.h>
#include <sqlite3.h>
int main(int argc, const char *argv[])
{
sqlite3 *db;
int ret = -1;
ret = sqlite3_open("test.db",&db);
if (0 != ret)
{
perror("open");
return -1;
}
char *sql = "create table if not exists student (name text, age interger, id interger);";
char *errmsg;
ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if (0 != ret)
{
fprintf(stderr, "%s", sqlite3_errmsg(db));
fprintf(stderr, "errmsg = %s",errmsg);
return -1;
}
char sqlbuf[1024] = "\0";
char name[128] = "\0";
int age, id;
//数据库 增加
printf(">>数据库增加\n");
printf("Please input your name: ");
scanf("%s", name);
printf("Please input your age: ");
scanf("%d", &age);
printf("Please input your id: ");
scanf("%d", &id);
sprintf(sqlbuf, "insert into student (name, age, id) values ('%s', '%d', '%d');", name, age, id);
ret = sqlite3_exec(db, sqlbuf, NULL, NULL, &errmsg);
if (0 != ret)
{
fprintf(stderr, "%s", sqlite3_errmsg(db));
fprintf(stderr, "errmsg = %s", errmsg);
return -1;
}
printf("数据库插入成功!\n");
//数据库 删除
printf(">>根据条件删除数据库\n");
printf("Please input your id: ");
scanf("%d",&id);
sprintf(sqlbuf,"delete from student where id = %d", id);
ret = sqlite3_exec(db, sqlbuf, NULL, NULL, &errmsg);
if (0 != ret)
{
fprintf(stderr, "%s", sqlite3_errmsg(db));
fprintf(stderr, "errmsg = %s", errmsg);
return -1;
}
printf("数据库删除成功!\n");
//数据库 查询
printf(">>根据条件查询数据库\n");
printf("Please input your name: ");
scanf("%s",name);
sprintf(sqlbuf, "select * from student where name = %s", name);
ret = sqlite3_exec(db, sqlbuf, NULL, NULL, &errmsg);
if (0 != ret)
{
fprintf(stderr, "%s", sqlite3_errmsg(db));
fprintf(stderr, "errmsg = %s", errmsg);
return -1;
}
printf("数据库查询成功!\n");
//数据库 更改
printf(">>更新数据库\n");
printf("Please input your name: ");
scanf("%s", name);
printf("Please input your age: ");
scanf("%d", &age);
printf("Please input your id: ");
scanf("%d", &id);
sprintf(sqlbuf, "update student set age = %d, id = %d where name = '%s';", age, id, name);
ret = sqlite3_exec(db, sqlbuf, NULL, NULL, &errmsg);
if (0 != ret )
{
fprintf(stderr, "%s", sqlite3_errmsg(db));
fprintf(stderr, "errmsg = %s", errmsg);
return -1;
}
printf("数据库更改成功!\n");
sqlite3_close(db); //关闭数据库
return 0;
}
------------------------------------------------------------------
下面是个回掉函数的实例:< sqlite_exec.c >
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#define MAX 100
//回掉函数
int show_sql_result(
void *argc,
int n_column,
char **column_value,
char **column_name
)
{
int i = 0;
int param = *((int *)argc);
printf("enter callback ---> param = %d, n_column = %d\n", param, n_column);
for (i = 0; i < n_column; i++)
{
printf("%s\t", column_name[i]);
}
printf("\n------------------------------------\n");
for (i = 0; i < n_column; i++)
{
printf("%s\t", column_value[i]);
}
printf("\n\n");
return 0;
}
//sqlite3_exec
int exec_sql_string(char *sql_string, sqlite3 *db)
{
char *errmsg = NULL; //防止出现野指针
int param = 100;
printf("before sqlite3_exec()\n");
if (SQLITE_OK != sqlite3_exec(
db,
sql_string,
show_sql_result,
¶m,
&errmsg))
{
if(NULL != errmsg)
{
fprintf(stderr, "Fail to exec sql(%s) : %s.\n", sql_string, errmsg);
sqlite3_free(errmsg);
}
else
{
fprintf(stderr, "Fail to exec sql(%s) : %s.\n", sql_string, errmsg);
}
return -1;
}
printf("after sqlite3_exec()");
return 0;
}
//主函数
int main(int argc, char *argv[])
{
sqlite3 *db = NULL;
int result;
char sql_buf[MAX];
/* 判断命令行参数 */
if (argc < 2)
{
fprintf(stderr, "usage : %s argv[1].\n", argv[0]);
exit(EXIT_FAILURE);
}
result = sqlite3_open(argv[1], &db); /* 打开数据库 */
//判断打开结果
if (SQLITE_OK != result)
{
if (NULL != db)
{
fprintf(stderr, "sqlite3_open %s : %s.\n",
argv[1], sqlite3_errmsg(db));
}
else
{
printf("error : failed to allocate memory for sqlite3!\n");
}
sqlite3_close(db);
exit(EXIT_FAILURE);
}
while (1)
{
printf("sqlite>");
if (NULL == fgets(sql_buf, sizeof(sql_buf), stdin))
continue;
sql_buf[strlen(sql_buf) - 1] = '\0'; /* eat up the ending '\n' */
if (0 == strncmp(sql_buf, ".quit", 5))
break;
exec_sql_string(sql_buf, db); //
}
result = sqlite3_close(db);
if (0 != result)
{
fprintf(stderr, "Fail to sqlite3_open %s : %s.\n", argv[1], sqlite3_errmsg(db));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
7、sqlite3_get_table
函数原型:
int sqlite3_get_table(
sqlite *pDb, /* An open database */
const char *sql, /* SQL to be evaluated */
char ***pResult, /*Results written to a char *[] that points to*/
int *rowCount, /* Number of result rows written here */
int *columnCount, /*Number of result columns written here */
char **errMsg /* Error msg written here */
)
函数功能:执行SQL语句,通过一维数组返回结果:一般用于数据记录查询
输入参数:
pDb,打开的数据库句柄;
sql, 待执行的SQL语句字符串,以’\0’结尾;
输出参数:
rowCount, 查询出多少条记录(即查出多少行,不包括字段名那行);
columnCount, 查询出来的记录有多少字段(即有多少列)
errMsg, 返回错误信息
pResult, 查询结果,是由字符串组成的一维数组(不要以为是二维数组)。
它的内存布局是:第一行是字段名称,后面紧接着每个字段的值;
pResult 返回的字符串数量实际上是(*pnRow+1) * (*pnColumn),因为前(*pnColumn)个是字段名。
返回值:执行成功返回SQLITE_OK,否则返回其他值。
8、关闭 sqlite 数据库sqlite3_free_table
函数原型:
void sqlite3_free_table(char **result);
函数功能:
输入参数:
输出参数:
返回值:
9、sqlite3_get_table获取数据内存分布
内存分布(即pResult查询结果的内存布局):
从第0索引到第columnCount-1索引都是字段的名称,从第columnCount索引开始,后面都是字段的值。


下面是个sqlite3_free_table 函数的实例:
< sqlite3_get_table.c >
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#define MAX 100
int exec_sql_string(char *sql_string, sqlite3 *db)
{
char *errmsg, **dbResult;
int nRow, nColumn;
int result, i, j, index;
result = sqlite3_get_table(
db,
sql_string,
&dbResult,
&nRow,
&nColumn,
&errmsg);
if (0 != result)
{
fprintf(stderr, "Fail to exec sql(%s) : %s.\n", sql_string, errmsg);
return -1;
}
//字段名字
for (j = 0; j < nColumn; j++)
{
printf("%s\t", dbResult[j]);
}
printf("\n");
index = nColumn; //从它开始是字段对应的值
for (i = 0; i < nRow; i++) //查询到总共记录个数
{
for (j = 0; j < nColumn; j++)
{
printf("%s\t", dbResult[index]);
index++;
}
printf("\n");
}
//释放查询结果所分配的内存
sqlite3_free_table(dbResult);
return 0;
}
int main(int argc, char *argv[])
{
sqlite3 *db = NULL;
int result;
char sql_buf[MAX];
if (argc < 2)
{
fprintf(stderr,"usage : %s argv[1].\n", argv[0]);
exit(EXIT_FAILURE);
}
result = sqlite3_open(argv[1], &db);
if (result != SQLITE_OK)
{
fprintf(stderr, "Fail to sqlite3_open %s : %s.\n",argv[1], sqlite3_errmsg(db));
exit(EXIT_FAILURE);
}
while (1)
{
printf("sqlite>");
if (NULL == fgets(sql_buf, sizeof(sql_buf), stdin))
continue;
sql_buf[strlen(sql_buf) - 1] = '\0';
if (0 == strncmp(sql_buf, ".quit", 5))
break;
exec_sql_string(sql_buf, db);
result = sqlite3_close(db);
if (result != 0)
{
fprintf(stderr, "Fail to sqlite3_open %s : %s.\n",argv[1], sqlite3_errmsg(db));
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
------------------------------------------------------------------
<sqlite3_get_table使用举例.c>
//sqlite3_get_table使用举例
void GetTable()
{
sqlite3 * db;
int result;
char * errmsg = NULL;
char **dbResult; //是 char ** 类型,两个*号
int nRow, nColumn;
int i , j;
int index;
result = sqlite3_open( “Dcg_database.db”, &db );
if(SQLITE_OK != result )
{
return -1; //数据库打开失败
}
//数据库操作代码
//假设前面已经创建了 MyTable_1 表
//开始查询,传入的 dbResult 已经是 char **,这里又加了一个 & 取地址符,传递进去的就成了 char ***
result = sqlite3_get_table(
db,
“select * from MyTable_1”,
&dbResult,
&nRow,
&nColumn,
&errmsg );
if( SQLITE_OK == result )
{
//查询成功
index = nColumn; //前面说过 dbResult 前面第一行数据是字段名称,从 nColumn 索引开始才是真正的数据
printf( “查到%d条记录\n”, nRow );
for( i = 0; i < nRow ; i )
{
printf( “第 %d 条记录\n”, i 1 );
for( j = 0 ; j < nColumn; j )
{
printf( “字段名:%s ?> 字段值:%s\n”, dbResult[j], dbResult [index] );
index;
// dbResult 的字段值是连续的,
//从第0索引到第 nColumn - 1索引都是字段名称,
//从第 nColumn 索引开始,后面都是字段值,
//它把一个二维的表(传统的行列表示法)用一个扁平的形式来表示
}
printf( “-------\n” );
}
}
//到这里,不论数据库查询是否成功,都释放 char** 查询结果,使用 sqlite 提供的功能来释放
sqlite3_free_table( dbResult );
//关闭数据库
sqlite3_close( db );
return 0;
}
}
------------------------------------------------------------------
< sqlite3_get.c >
/*************************************************************************
> File Name: sqlite3_open.c
> Author: Zhang
> Mail:
> Created Time: 2017年06月08日 星期四 16时32分40秒
************************************************************************/
#include <stdio.h>
#include <sqlite3.h>
int main(int argc, const char **argv)
{
sqlite3 *db;
int ret = -1;
char sqlbuf[1024] = "\0";
char name[128] = "\0";
int age, id;
char **result;
int nrow, ncolumn;
char *errmsg;
int i, j;
ret = sqlite3_open("test.db", &db);
if(ret != 0)
{
perror("open");
return -1;
}
sprintf(sqlbuf, "select * from student;");
ret = sqlite3_get_table(db, sqlbuf, &result, &nrow, &ncolumn, &errmsg);
if(0 != ret)
{
fprintf(stderr, "get_table failed:%s", errmsg);
return -1;
}
for(i = 0; i < ncolumn; i++)
{
printf("%8s ", result[i]);
}
printf("\n-----------------------------------------------------\n");
for(i = 1; i <= nrow; i++)
{
for(j = 0; j < ncolumn; j++)
{
printf("%8s ", result[i*ncolumn+j]);
}
}
printf("\n");
sqlite3_free_table(result);
sqlite3_close(db);
return 0;
}
------------------------------------------------------------------
< 3_p.c >
#include <stdio.h>
#include <stdlib.h>
/*
* 这个测试程序主要是为了测试sqlite_get_table中三级指针的作用
* 这边使用三级指针主要是为了传递一个二级指针的地址
* 这个二级指针应实际指向的应该时一个(指针数组)
* */
void fun(char ***p, int column, int row)
{
/*
* 三级指针p存放的是二级指针的地址,*p代表二级指针的内容即
* 一级指针的地址(指针数组的首地址)
* (**p)代表一级指针的内容即字符串的首地址
* */
*p = (char **)malloc(sizeof(*p) * column * row);
/*
*这边malloc申请的空间应当是指针数组的空间
*使用*p(二级指针)指向malloc 返回的首地址
*注意强制类型转换成二级指针
* */
**p = "name";
*(*p+1) = "id";
*(*p+2) = "lu";
*(*p+3) = "1";
printf("%p\n",*p);
printf("%p\n",&(**p));
printf("%p\n",&(*(*p+1)));
printf("%p\n",&(*(*p+2)));
return ;
}
int main(int argc, const char *argv[])
{
char **p;
int column = 2,row = 3;
fun(&p, column, row);
printf("%s\n",p[0]);
printf("%s\n",p[1]); //? 0x1d91018
printf("%s\n",p[2]); //? 0x1d91020
free(p);
return 0;
}
// 运行结果
// allure@ubuntu:~/Jeff/SQLite$ ./3_p
// 0x1d91010
// 0x1d91010
// 0x1d91018
// 0x1d91020
// name
// id
// lu
#include <stdio.h>
#include <stdlib.h>
/*
* 這個測試程序主要是爲了測試sqlite_get_table中三級指針的作用
* 這邊使用三級指針主要是爲了傳遞一個二級指針的地址
* 這個二級指針應實際指向的應該時一個(指針數組)
* */
void fun(char ***p, int column, int row)
{
/*
* 三級指針p存放的是二級指針的地址,*p代表二級指針的內容即
* 一級指針的地址(指針數組的首地址)
* (**p)代表一級指針的內容即字符串的首地址
* */
*p = (char **)malloc(sizeof(*p) * column * row);
/*
*這邊malloc申請的空間應當是指針數組的空間
*使用*p(二級指針)指向malloc 返回的首地址
*注意強制類型轉換成二級指針
* */
**p = "name";
*(*p+1) = "id";
*(*p+2) = "lu";
*(*p+3) = "1";
printf("%p\n",*p);
printf("%p\n",&(**p));
printf("%p\n",&(*(*p+1)));
printf("%p\n",&(*(*p+2)));
return ;
}
int main(int argc, const char *argv[])
{
char **p;
int column = 2,row = 3;
fun(&p, column, row);
printf("%s\n",p[0]);
printf("%s\n",p[1]); //? 0x1d91018
printf("%s\n",p[2]); //? 0x1d91020
free(p);
return 0;
}
// 运行结果
// allure@ubuntu:~/Jeff/SQLite$ ./3_p
// 0x1d91010
// 0x1d91010
// 0x1d91018
// 0x1d91020
// name
// id
// lu