linux 下sqlite的 C编程之sqlite3_get_table

说明:通过sqlite3_get_table查询得到的结果,其结构是:第一行是列名,随后的行才是值。遍历的方式和二维数组相同。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include "test.h"
int main(int argc, char **argv)
{
        sqlite3 *db;
        char **dbResult; 
        char *errmsg;
        int nRow, nColumn;
        int index=0;
        int i, j, rc;

        if( argc!=2 )
        {
                fprintf(stderr, "Usage: %s DATABASE \n", argv[0]);
                exit(1);
        }

        rc = sqlite3_open(argv[1], &db);
        if( rc != SQLITE_OK )
        {
                fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
                sqlite3_close(db);
                exit(1);
        }

        rc = sqlite3_get_table( db, "select * from users", &dbResult, &nRow, &nColumn, &errmsg);
        if (rc == SQLITE_OK)
        {
                printf("表格共%d 记录!\n", nRow);
                printf("表格共%d 列!\n", nColumn);
                // 前两个字段为字段名 field0, field1, row[0][0], row[0][1], row[1][0], row[1][1] ... ... ....
                // 是一维数组,不是二维数组,反正记着第0,第1列的值为字段名,然后才是字段值;
                printf( "字段名|字段值\n");
                printf( "%s | %s\n", dbResult[0], dbResult[1]);
                printf("--------------------------------\n");
                index = nColumn; //字段值从index开始呀
                for( i = 0; i < nRow ; i++ )
                {
                        for( j = 0 ; j < nColumn; j++ )
                        {
                                printf( "%-5s ",dbResult[index++]);
                        }
                        printf("\n");
                }
                printf("--------------------------------\n");
        }

        sqlite3_close(db);
        return 0;
}
/*     test.h是为空的    */


makefile如下:
all: test
CC=gcc -g -Wall
clean:
        @rm -rf *.o
test: test.o
        $(CC) -ldl -lsqlite3 -o test test.o
test.o: test.c test.h
        $(CC) -c test.c
red hat as4 下编译通过

----------------------------------------------------------------------

SQLite 的 C 语言编程
执行sql语句
int
sqlite3_exec ( sqlite3 *db,  // 使用 sqlite3_open () 打开的数据库对象。
               const char *sql, // 一条待查询的 SQL 语句
               sqlite3_callback, // 自定义的回调函数,对查询结果每一行都执行一次这个函数
               void *,
               char **errmsg
);
<example>

这是最常用的执行 sql 语句的调用。简单的参数含意标在上面函数中,下面对重
要参数含意详细注释:

 - 第 4 个参数 "void *" 是调用者所提供的指针,可以传递任何一个指针参数到
   这里,这个参数最终会传到回调函数里面,这个指针比较重要,可以用来作参
   数的传递。如果不需要传递指针给回调函数,可以填NULL。等下我们再看回调
   函数的写法,以及这个参数的使用。

 - 第 5 个参数 "char ** errmsg" 是错误信息。注意是指针的指针。sqlite3里
   面有很多固定的错误信息。执行 sqlite3_exec 之后,执行失败时可以查阅这
   个指针(直接 printf(“%s\n”,errmsg))得到一串字符串信息,这串信息告诉
   你错在什么地方。sqlite3_exec函数通过修改你传入的指针的指针,把你提供
   的指针指向错误提示信息,这样sqlite3_exec函数外面就可以通过这个
   char*得到具体错误提示。

说明:通常, sqlite3_callback 和它后面的 void * 这两个位置都可以填
NULL。填NULL表示你不需要回调。比如你做 insert 操作,做 delete 操作,就
没有必要使用回调。而当你做 select 时,就要使用回调,因为 sqlite3 把数据
查出来,得通过回调告诉你查出了什么数据。

** exec 的回调函数
<example>
typedef int
(*sqlite3_callback) (void *, // 这就是上面函数传递的 void * 参数,需要强制类型转换后才能使用。
                    int, // 查询结果的列数,即有多少个字段数
                    char **, // 保存查询结果
                    char **  // 各个字段的名字
);

回调函数必须定义成上面这个函数的类型。下面给个简单的例子:

不使用回调查询数据库
上面介绍的 sqlite3_exec 是使用回调来执行 select 操作。还有一个方法可以直接查询而不需要回调。虽然回调显得代码整齐,但有时候你还是想要非回调的 select 查询。这可以通过 sqlite3_get_table 函数做到。

int
sqlite3_get_table (sqlite3 *,   // 打开的数据库对象指针
                   const char * sql, // 要查询的 sql 语句
                   char *** resultp, // 查询结果
                   int * nrow,   // 查询出多少条记录(即查出多少行)
                   int * ncolumn, // 多少个字段(多少列)
                   char ** errmsg  // 错误信息
);

第3个参数是查询结果,它依然一维数组(不要以为是二维数组,更不要以为是三维数组)。它内存布局是:第一行是字段名称,后面是紧接着是每个字段的值。下面用例子来说事。

下面给个简单例子:

int main( int , char ** )
{
          sqlite3 * db;
          int result;
          char * errmsg = NULL;
          char ** dbResult; //是 char ** 类型,两个*号
          int nRow, nColumn;
          int i , j;
          int index;

          result = sqlite3_open( “c:\\Dcg_database.db”, &db );

         if( result != SQLITE_OK )
        {
               //数据库打开失败
               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;
}

操作二进制
sqlite 操作二进制数据需要用一个辅助的数据类型:sqlite3_stmt * 。这个数据类型记录了一个“sql语句”。为什么我把 “sql语句” 用双引号引起来?因为你可以把 sqlite3_stmt * 所表示的内容看成是 sql语句,但是实际上它不是我们所熟知的sql语句。它是一个已经把sql语句解析了的、用sqlite自己标记记录的内部数据结构。正因为这个结构已经被解析了,所以你可以往这个语句里插入二进制数据。当然,把二进制数据插到 sqlite3_stmt 结构里可不能直接 memcpy ,也不能像 std::string 那样用 + 号。必须用 sqlite 提供的函数来插入。

写入二进制
要插入二进制,前提是这个表的字段的类型是 blob 类型。假设有这么一张表:

create table Tbl_2( ID integer, file_content  blob )

首先声明

sqlite3_stmt * stat;

然后,把一个 sql 语句解析到 stat 结构里去:

sqlite3_prepare( db, “insert into Tbl_2( ID, file_content) values( 10, ? )”, -1, &stat, 0 );

上面的函数完成 sql 语句的解析。

第一个参数跟前面一样,是个 sqlite3 * 类型变量 
第二个参数是一个 sql 语句。这个 sql 语句特别之处在于 values 里面有个 ? 号。在sqlite3_prepare函数里,?号表示一个未定的值,它的值等下才插入。
第三个参数我写的是-1,这个参数含义是前面 sql 语句的长度。如果小于 0,sqlite会自动计算它的长度(把sql语句当成以\0结尾的字符串)。 
第四个参数是 sqlite3_stmt 的指针的指针。解析以后的sql语句就放在这个结构里。 
第五个参数我也不知道是干什么的。为0就可以了。 
如果这个函数执行成功(返回值是 SQLITE_OK 且 stat 不为NULL ),那么下面就可以开始插入二进制数据。

sqlite3_bind_blob( stat, 1, pdata, (int)(length_of_data_in_bytes), NULL );
// pdata为数据缓冲区,length_of_data_in_bytes为数据大小,以字节为单位

这个函数一共有5个参数。

第 1 个参数:是前面prepare得到的 sqlite3_stmt * 类型变量。 
第 2 个参数:?号的索引。前面prepare的sql语句里有一个?号,假如有多个?号怎么插入?方法就是改变 bind_blob 函数第2个参数。这个参数我写1,表示这里插入的值要替换 stat 的第一个?号(这里的索引从1开始计数,而非从0 开始)。如果你有多个?号,就写多个 bind_blob 语句,并改变它们的第2个参数就替换到不同的?号。如果有?号没有替换,sqlite为它取值null。 
第3个参数:二进制数据起始指针。 
第4个参数:二进制数据的长度,以字节为单位。 
第5个参数:是个析够回调函数,告诉sqlite当把数据处理完后调用此函数来析够你的数据。这个参数我还没有使用过,因此理解也不深刻。但是一般都填 NULL,需要释放的内存自己用代码来释放。 
bind完了之后,二进制数据就进入了你的“sql语句”里了。你现在可以把它保存到数据库里:

int result = sqlite3_step( stat );

通过这个语句,stat 表示的sql语句就被写到了数据库里。最后,要把 sqlite3_stmt 结构给释放: 
sqlite3_finalize( stat ); //把刚才分配的内容析构掉

读出二进制
先声明 sqlite3_stmt * 类型变量:

sqlite3_stmt * stat;

然后,把一个 sql 语句解析到 stat 结构里去:

sqlite3_prepare( db, “select * from Tbl_2”, -1, &stat, 0 );

当 prepare 成功之后(返回值是 SQLITE_OK ),开始查询数据。

int result = sqlite3_step( stat );

这一句的返回值是 SQLITE_ROW 时表示成功(不是 SQLITE_OK )。

你可以循环执行 sqlite3_step 函数,一次 step 查询出一条记录。直到返回值不为 SQLITE_ROW 时表示查询结束。

然后开始获取第一个字段:ID 的值。ID是个整数,用下面这个语句获取它的值:

int id = sqlite3_column_int( stat, 0 );
//第2个参数表示获取第几个字段内容,从0开始计算,因为我的表的ID字段是第一个字段,因此这里我填0

下面开始获取 file_content 的值,因为 file_content 是二进制,因此我需要得到它的指针,还有它的长度:

const void * pFileContent = sqlite3_column_blob( stat, 1 );
int len = sqlite3_column_bytes( stat, 1 );

这样就得到了二进制的值。把 pFileContent 的内容保存出来之后,不要忘了释放 sqlite3_stmt 结构:

sqlite3_finalize( stat ); //把刚才分配的内容析构掉

重复使用 sqlite3_stmt 结构
如果你需要重复使用 sqlite3_prepare 解析好的 sqlite3_stmt 结构,需要用函数: sqlite3_reset。

result = sqlite3_reset(stat);

这样, stat 结构又成为 sqlite3_prepare 完成时的状态,你可以重新为它 bind 内容。

------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"

#include <string.h>

int main(int argc, char **argv)
{
    int rc, i, ncols;
    sqlite3 *db;
    sqlite3_stmt *stmt;
    char *sql;
    const char *tail;
    //打开数据
    rc = sqlite3_open("foods.db", &db);

    if(rc) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        exit(1);
    }
    
    sql = "select * from episodes";
    //预处理
    rc = sqlite3_prepare(db, sql, (int)strlen(sql), &stmt, &tail);

    if(rc != SQLITE_OK) {
        fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
    }
    
    rc = sqlite3_step(stmt);
    ncols = sqlite3_column_count(stmt);

    while(rc == SQLITE_ROW) {
        
        for(i=0; i < ncols; i++) {
            fprintf(stderr, "'%s' ", sqlite3_column_text(stmt, i));
        }

        fprintf(stderr, "\n");

        rc = sqlite3_step(stmt);
    }
    //释放statement
    sqlite3_finalize(stmt);
    //关闭数据库
    sqlite3_close(db);

    return 0;    
}
---------------------------------------------------------------

参看API说明://http://www.sqlite.org/cintro.html

编译器:VC6.0
数据库:sqlite
头文件包:sqlite-amalgamation-3070601
使用时将sqlite3.h,sqlite3.c拷到目录下,或者直接添加include路径

#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
//回调函数print的编写;
//其中data为sqlite3_exec中的第四个参数
//第二个参数是栏的数目
//第三个是栏的名字
//第四个为查询得到的值得
//这两个函数输出所有查询到的结果
//该函数会被插入到每一行结果中
int print(void *data, int n_columns, char **column_values, char **column_names)
{
        int i;
        for(i = 0; i < n_columns; ++i)
                printf("列名:%s\n列值:%s\n", column_names[i], column_values[i]);
        return 0;
}
char *datafile = "test.s3db";
char *createsql = "CREATE TABLE [test] ([id] INTEGER    NOT NULL PRIMARY KEY AUTOINCREMENT, [name] TEXT    NOT NULL, [sex] TEXT    NOT NULL);";
char *selectsql = "select * from test";
char *insertsql = "insert into test(name, sex) values(\'hahahah\', \'man\');";
char *deletesql = "delete from test where id < 6;";
int main(void)
{
        sqlite3 *db=NULL;
        char *errMsg;
        int rc;
        //打开一个数据库,如果改数据库不存在,则创建一个名字为datafile的数据库文件
        if((rc = sqlite3_open(datafile, &db)) != SQLITE_OK)
        {
                fprintf(stderr, "打开数据库失败: %s\n", sqlite3_errmsg(db));
                return 0;
        }
        else
        {
                if((rc = sqlite3_exec(db, createsql, 0, 0, &errMsg)) != SQLITE_OK)
                {
                        printf("创建数据库失败:%s\n", errMsg);
                        return 0;
                }
                else
                {
                        printf("创建表test成功\n");
                }
        }
        if((rc = sqlite3_exec(db, selectsql, print, 0, &errMsg)) != SQLITE_OK)//查询
        {
                printf("查询错误:%s\n", errMsg);
        }
        printf("插入操作=========================================\n");
        if((rc = sqlite3_exec(db, insertsql, 0, 0, &errMsg)) != SQLITE_OK)//删除
        {
                printf("插入错误:%s\n", errMsg);
        }
        if((rc = sqlite3_exec(db, selectsql, print, 0, &errMsg)) != SQLITE_OK)//查询
        {
                printf("查询错误:%s\n", errMsg);
        }
        printf("删除操作=========================================\n");
        if((rc = sqlite3_exec(db, deletesql, 0, 0, &errMsg)) != SQLITE_OK)//删除
        {
                printf("删除错误:%s\n", errMsg);
        }
        if((rc = sqlite3_exec(db, selectsql, print, 0, &errMsg)) != SQLITE_OK)//查询
        {
                printf("查询错误:%s\n", errMsg);
        }
        printf((sqlite3_close(db) == SQLITE_OK)?"close sqlite success\n":"close sqlite failed\n");//关闭数据库
        return 0;
}
-----------------------------------------------------------------
// name: query.c
// This prog is used to test C/C++ API for sqlite3 .It is very simple,ha !
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h" 
//#define _DEBUG_

int main( void )
{
 sqlite3 *db=NULL;
 char *zErrMsg = 0;
 char *dbPath = "/usr/tomcat6/webapps/sql/WEB-INF/classes/sq3.s3db";

 int rc;
 
 rc = sqlite3_open(dbPath, &db); //打开指定的数据库文件,如果不存在将创建一个同名的数据库文件
 if( rc )
 {
  fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
  sqlite3_close(db);
  exit(1);
 }
 else 
 {
  printf("You have opened a sqlite3 database saved in %s successfully!\n",dbPath);
 }
 

 //创建一个表,如果该表存在,则不创建,
 //返回值为SQLITE_OK为成功
 //函数参数:第一个为操作数据库的指针,第二句为SQL命令字符串
 //第三个参数为callback函数,这里没有用,第四个参数为callback函数
 //第五个参数给出提示信息,存储在 zErrMsg 中
 char *sql = " CREATE TABLE SensorData(\
      ID INTEGER PRIMARY KEY,\
     SensorID INTEGER,\
      SiteNum INTEGER,\
      Time VARCHAR(12),\
      SensorParameter REAL\
      );" ;
 sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );

 #ifdef _DEBUG_
        printf("zErrMsg = %s \n", zErrMsg);
    #endif
 
 //插入数据 
 sql = "INSERT INTO \"SensorData\" VALUES(NULL , 1 , 1 , '200605011206', 18.9 );" ;
 sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
 
 sql = "INSERT INTO \"SensorData\" VALUES(NULL , 1 , 1 , '200605011306', 16.4 );" ;
 sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
 
 
  
 int nrow = 0, ncolumn = 0;
 char **azResult; //二维数组存放结果

 //查询数据
 /*
 int sqlite3_get_table(sqlite3*, const char *sql,char***result , int *nrow , int *ncolumn ,char **errmsg );
 result中是以数组的形式存放你所查询的数据,首先是表名,再是数据。
 nrow ,ncolumn分别为查询语句返回的结果集的行数,列数,没有查到结果时返回0
 */
 sql = "SELECT * FROM SensorData ";
 sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );

 int i = 0 ;
 printf( "row:%d column=%d \n" , nrow , ncolumn );
 printf( "\nThe result of querying is : \n" );
 
 for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )
  printf( "azResult[%d] = %s\n", i , azResult[i] );

 //释放掉  azResult 的内存空间
 sqlite3_free_table( azResult );
  
 #ifdef _DEBUG_
        printf("zErrMsg = %s \n", zErrMsg);
    #endif

 sqlite3_close(db); //关闭数据库
 return 0;
 
}
--------------------------------------------------------

.5 写个C语言程序调用SQLite
    现在我们来写个C/C++程序,调用 sqlite    的 API 接口函数。
    下面是一个C程序的例子,显示怎么使用 sqlite 的 C/C++ 接口. 数据库的名字由第一个参数取得且第二个参数或更多的参数是 SQL 执行语句. 这个函数调用sqlite3_open() 在 22 行打开数据库, sqlite3_exec() 在 27 行执行 SQL 命令, 并且sqlite3_close() 在 31 行关闭数据库连接。
代码:

//     name: opendbsqlite.c
//    This file is used to test C/C++ API for sqlite
//     Author : zieckey
//     2006/04/11
#include 
#include

int main( void )
{
    sqlite3 *db=NULL;
    char *zErrMsg = 0;
    int rc;
    rc = sqlite3_open("zieckey.db", &db);   //打开指定的数据库文件,如果不存在将创建一个同名的数据库文件
    if( rc ){
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        exit(1);
    }
    else printf("open zieckey.db successfully!\n");
   
    sqlite3_close(db);                //关闭数据库
    return 0;
}

编译:# gcc opendbsqlite.c -o db.out
也许会碰到类似这样的问题:
/tmp/ccTkItnN.o(.text+0x2b): In function `main':
: undefined reference to `sqlite3_open'
/tmp/ccTkItnN.o(.text+0x45): In function `main':
: undefined reference to `sqlite3_errmsg'
/tmp/ccTkItnN.o(.text+0x67): In function `main':
: undefined reference to `sqlite3_close'
/tmp/ccTkItnN.o(.text+0x8f): In function `main':
: undefined reference to `sqlite3_close'
collect2: ld returned 1 exit status

这是个没有找到库文件的问题。
由于用到了用户自己的库文件,所用应该指明所用到的库,我们可以这样编译:

# gcc opendbsqlite.c -o db.out -lsqlite3

我用用 -lsqlite3 选项就可以了(前面我们生成的库文件是 libsqlite3.so.0.8.6 等,
去掉前面的lib和后面的版本标志,就剩下 sqlite3 了所以是 -lsqlite3 )。
如果我们在编译安装的时候,选择了安装路径,例如这样的话:
.......
# ../sqlite/configure --prefix=/usr/local/arm-linux/sqlite-ix86-linux
.......
这样编译安装时,sqlite的库文件将会生成在  /usr/local/arm-linux/sqlite-ix86-linux/lib 目录下
这时编译还要指定库文件路径,因为系统默认的路径没有包含 /usr/local/arm-linux/sqlite-ix86-linux/lib

# gcc opendbsqlite.c -lsqlite3 -L/usr/local/arm-linux/sqlite-ix86-linux/lib

如果还不行的话,可能还需要指定头文件 sqlite3.h 的路径,如下:

# gcc opendbsqlite.c -lsqlite3 -L/usr/local/arm-linux/sqlite-ix86-linux/lib -I/usr/local/arm-linux/sqlite-ix86-linux/include

这样编译应该就可以了 ,运行:
# ./db.out
open zieckey.db successfully!
是不是很有成就感阿 ,呵呵,这个上手还是很快的。 
------------------------------------------------------------------------------------------
一、SQLite简介
SQLite 支持多数SQL92标准,例如:索引、限制、触发和查看支持。支持 NULL、INTEGER、REAL、TEXT 和 BLOB 数据类型,支持事务。 
sqlite支持的sql92标准有:
begin transaction;end transaction;commit transaction;rollback transaction;select,update,delete,insert
create index,table,trigger,view
drop index,table,trigger,view

SQLite 实现了完备的、可嵌入的、零配置的SQL数据库引擎。它的特点包括 [2]: 
1. 事务处理是原子的、一致的、独立的和持久的(ACID),即使在系统崩溃和掉电以后。 
2. 零配置,即不需要设置和管理。 
3. 实现了绝大部分的SQL92标准。 
4. 一个单独的磁盘文件存储一个完整的数据库。 
5. 数据库文件在机器之间可自由共享。 
6. 支持数据库文件大小至2TB. 
7. 字符串和BLOG的大小只受限于可用存储器容量。 
8. 代码量小,即小于30K的C代码行和小于250K的代码空间(gcc 在i486上) 
9. 对于绝大多数普通操作来说,比流行的C/S 模式的数据库引擎运行速度快。 
10. API 简单、易用。

 


二、下载SQLite
SQLite可以到官方站点下载 http://www.sqlite.org/download.html 包括:Linux,Mac OS X, Windows下的已编译文件以及源代码、帮助文档。 
1.下载sqlite库文件(放到e:\sqlite\sqlite3.exe)
2.在CMD下进入到e:\sqlite下
3.在CMD下输入sqlite3.exe c:\\test.db; (打开数据库;c:\\test.db不存在则创建)
4.进入数据库后就可以使用sql的四个命令了;(注意sql命令必须加;号)
5.两个工具:Sqlite Developer和SQLite Administrator

 


三、SQLite的简单使用

3.1 建立数据库 C:\sqlite-3_6_11> sqlite3.exe dbname.db //sqlite3.exe后面跟数据库文件名3.2 创建数据表 sqlite> create table users(userid varchar(20) PRIMARY KEY, age int, birthday datetime);3.3 添加记录 insert into users values('张三',20,'1989-05-04');3.4 查询记录  select * from users order by birthday;
3.5 删除记录  delete from users where userid='wang';
3.6 退出sqlite  sqlite> .exit

SQLite数据库的数据结构是存贮在 "sqlite_master" 表中 具体命令可以输入 .help查看或参考帮助文档
.database              显示文件中的数据库列表(没有附加数据库,则只有main数据库)
.table                 罗列出所有的表名称
.dump                  以sql格式输出表结构和表中的数据
.schem                 以sql格式输出表结构
.separator str         设置分隔符
.import file table     将文件中数据导入到表中;各字段以separator为分隔符(默认|分割符)
.output file&stdout    设置查询输出到文件中或屏幕上
.read file             执行文件中的sql语句
.backup ?db? file      备份数据库(不附加数据库, test.db文件中只有main数据库)
.restore ?db? file     恢复数据库
.head on|off           select查询的时候显示隐藏字段名
.indices table         列出表的索引名称.nullvalue STRING      用STRING代替null值显示


四、编译LIB
需要到SQLite网站下载sqlitedll-3_6_11.zip,以VS 2008为例:

在DOS命令行下:
PATH = D:\Program Files\Microsoft Visual Studio 9.0\VC\bin;%PATH% PATH = D:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE;%PATH% LIB /DEF:sqlite3.def /machine:IX86

 


五、在VC下使用
#include "../sqlite3_lib/sqlite3.h" // 加入头文件 #pragma comment(lib, "../sqlite3_lib/sqlite3.lib") // 链接lib库

#include"../sqlite3_lib/sqlite3.h"// 头文件
#pragma comment(lib, "../sqlite3_lib/sqlite3.lib") // lib静态库

// select_callback是select的回调函数
// @data : 是sqlite3_exec()中的第四个参数
// @col_count : 选择出来的列的个数
// @col_values: 每条记录每一列的数值
// @col_Name : 每一列的列名
staticint select_callback(void * data, int col_count, char ** col_values, char ** col_Name)
{
// 每条记录回调一次该函数,有多少条就回调多少次
int i;
for ( i=0; i < col_count; i++ )
{
printf( "%s = %s\n", col_Name[i], col_values[i] == 0 ? "NUL" : col_values[i] );
}

return 0;
}

int main(int argc, char * argv[])
{
constchar * sSQL1 = "create table users(userid varchar(20) PRIMARY KEY, age int, birthday datetime);";
char * pErrMsg = 0;


// 连接数据库
sqlite3 * db = 0;
int ret = sqlite3_open("./test.db", &db);
if ( ret != SQLITE_OK )
{
fprintf(stderr, "无法打开数据库: %s", sqlite3_errmsg(db));
return(1);
}
printf("数据库连接成功!\n");


// 执行建表SQL
sqlite3_exec( db, sSQL1, 0, 0, &pErrMsg );
if ( ret != SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", pErrMsg);
sqlite3_free(pErrMsg);
}


// 执行插入记录SQL
sqlite3_exec( db, "insert into users values('张三',20,'2001-5-4');", 0, 0, &pErrMsg);
sqlite3_exec( db, "insert into users values('李四',20,'1970-5-4');", 0, 0, &pErrMsg);


// 查询数据表, 第四个参数可以传递给回调函数
sqlite3_exec( db, "select * from users;", select_callback, NULL, &pErrMsg);


// 关闭数据库
sqlite3_close(db);
db = 0;

return 0;
}


 总结: 
正如SQLite的名称,SQLite有其适合的应用环境,对于高流量或数据庞大的Web站点,还是应该考虑使用DBMS

打开数据库: 
说明:打开一个数据库,文件名不一定要存在,如果此文件不存在, sqlite 会自动创建。第一个参数指文件名,第二个参数则是定义的 sqlite3 ** 结构体指针(关键数据结构),这个结构底层细节如何,您不用管它。 
int sqlite3_open( 
  const char *filename,   /* Database filename (UTF-8) */ 
  sqlite3 **ppDb           /* OUT: SQLite db handle */ 
);   
返回值:表示操所是否正确( SQLITE_OK 操作正常)

 

2、关闭数据库: 
说明:如果用 sqlite3_open 开启了一个数据库,结尾时不要忘了用这个函数关闭数据库。 
int sqlite3_close(sqlite3*);   // 参数就是刚才的结构体,也就是数据库句柄 
//注意在此出错后,可以用sqlite3_errmsg(db)来获得错误代码

 

3 、执行 SQL 语句: 
说 明:这个函数的功能是执行一条或者多条 SQL语句,SQL 语句之间用 “;” 号隔开。建议在执行一条或者多条 SQL 语句得时候,指定第三个参数回调函数,在 回调函数中可以获得执行 Sql 得详细过程,如果所有 Sql 执行完毕则应该返回 0 ,否则,则说明这次执行并没有完全成功。第五个参数:如果执行失败(没有返回 0 )则可以查看第五个阐述得值。来查看详细错误信息。 
int sqlite3_exec( 
    sqlite3*,             /* 已经打开的数据库句柄 */ 
    const char *sql,   /* 要执行的 Sql 语句 */ 
    sqlite_callback,    /* 回调函数 */ 
    void *,               /* 传递给回调函数的参数 */ 
    char **errmsg    /* 保存错误信息,注意用sqlite3_free(errmsg)来释放资源 */ 
); 
通常sqlite3_callback和后面的void*这两个位置都可以填 NULL,表示不需要回调。比如您做 insert,update,delete操作,就没有必要使用回调。而当作select时,就要使用回调,因为 sqlite3把数据查出来,得通过回调告诉你查出了什么数据。

 

4 、 exec 的回调 
typedef int (*sqlite3_callback)(void* data, int col_count, char** col_value, char** col_name); 
说明:你的回调函数必须定义为上面这个函数的类型。 
// select_callback是select的回调函数 
// @data : 是sqlite3_exec()中的第四个参数 
// @col_count : 选择出来的列的个数 
// @col_values: 每条记录每一列的数值 
// @col_Name : 每一列的列名 
static int select_callback(void * data, int col_count, char ** col_values, char ** col_Name)

#include"../sqlite3_lib/sqlite3.h"// 头文件
#pragma comment(lib, "../sqlite3_lib/sqlite3.lib") // lib静态库

// select_callback是select的回调函数
// @data : 是sqlite3_exec()中的第四个参数
// @col_count : 选择出来的列的个数
// @col_values: 每条记录每一列的数值
// @col_Name : 每一列的列名
staticint select_callback(void * notused, int argc, char ** values, char ** colName)
{
// 每条记录回调一次该函数,有多少条就回调多少次
int i;
for ( i=0; i < argc; i++ )
{
printf( "%s = %s\n", colName[i], values[i] == 0 ? "NUL" : values[i] );
}

return 0;
}

int main(int argc, char * argv[])
{
constchar * sSQL1 = "create table users(userid varchar(20) PRIMARY KEY, age int, birthday datetime);";
char * pErrMsg = 0;


// 连接数据库
sqlite3 * db = 0;
int ret = sqlite3_open("./test.db", &db);
if ( ret != SQLITE_OK )
{
fprintf(stderr, "无法打开数据库: %s", sqlite3_errmsg(db));
return(1);
}
printf("数据库连接成功!\n");


// 执行建表SQL
sqlite3_exec( db, sSQL1, 0, 0, &pErrMsg );
if ( ret != SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", pErrMsg);
sqlite3_free(pErrMsg);
}


// 执行插入记录SQL
sqlite3_exec( db, "insert into users values('张三',20,'2001-5-4');", 0, 0, &pErrMsg);
sqlite3_exec( db, "insert into users values('李四',20,'1970-5-4');", 0, 0, &pErrMsg);


// 查询数据表
sqlite3_exec( db, "select * from users;", select_callback, 0, &pErrMsg);


// 关闭数据库
sqlite3_close(db);
db = 0;

return 0;
}

 

5 、取当前插入位置: 
long long int sqlite3_last_insert_rowid(sqlite3*); 
功能:返回你前一次插入得位置,从1开始,sqlite3*为你打开数据库所得到得句柄。

 

6、非回调select查询: 
功能:执行一次查询 Sql 并且返回得到一个记录集。 
int sqlite3_get_table( 
    sqlite3*,        /* 已经打开的数据库句柄 */ 
    const char *sql, /* 要执行的 Sql 语句 */ 
    char ***resultp, /* 保存返回记录集的指针 */ 
    int *nrow,       /* 返回记录数(多少行) */ 
    int *ncolumn,    /* 返回字段数(多少列) */ 
    char **errmsg    /* 返回错误信息 */ 

说明:第三个参数是查询结果,它是一维数组,内存布局为(n行m列结果),那么数组的0到m-1行是列名,m到2*m-1是记录集的第一行数据,以后的以此类推;


#include"../sqlite3_lib/sqlite3.h"// 头文件
#pragma comment(lib, "../sqlite3_lib/sqlite3.lib") // lib静态库
int main( int , char ** )
{
sqlite3 * db;
int result;
char * errmsg = NULL;
char **dbResult;
int nRow, nColumn;
int i , j;
int index;

// 打开数据库
result = sqlite3_open( "./test.db", &db );
if( result != SQLITE_OK )
{
return -1;
}

// 数据库操作代码
// 假设前面已经创建了 MyTable_1 表
// 开始查询,传入的dbResult已经是char**,这里又加了一个&取地址符,传递进去的就成了char***
result = sqlite3_get_table( db, "select * from users;", &dbResult, &nRow, &nColumn, &errmsg );
if( SQLITE_OK == result )
{
// 查询成功 
printf( "查到 %d 条记录,ncolumn=%d \n", nRow, nColumn);
for( i = 1; i <= nRow ; i++ )
{
printf( "第 %d 条记录 \n", i );
for( j = 0 ; j < nColumn; j++ )
{
printf( " 字段名 :%s > 字段值 :%s\n", dbResult[j], dbResult[i*nColumn + j] );
// dbResult的字段值是连续的,从第0索引到第nColumn-1索引都是字段名称,从第nColumn索引开始,
// 后面都是字段值,它把一个二维的表(传统的行列表示法)用一个扁平的形式来表示 
}
printf( "-------\n" );
}
}

// 到这里,不论数据库查询是否成功,都释放 char** 查询结果,使用 sqlite 提供的功能来释放 
sqlite3_free_table( dbResult );

// 关闭数据库 
sqlite3_close( db );
return 0;
}

 

7 、释放查询结果: 
功能:释放当前查询的记录集所占用的内存 
void sqlite3_free_table(char **result);

1.0 总览
SQLite3是SQLite一个全新的版本,它虽然是在SQLite 2.8.13的代码基础之上开发的,但是使用了和之前的版本不兼容的数据库格式和API. SQLite3是为了满足以下的需求而开发的:

支持UTF-16编码. 
用户自定义的文本排序方法. 
可以对BLOBs字段建立索引. 
因此为了支持这些特性我改变了数据库的格式,建立了一个与之前版本不兼容的3.0版. 至于其他的兼容性的改变,例如全新的API等等,都将在理论介绍之后向你说明,这样可以使你最快的一次性摆脱兼容性问题.

3.0版的和2.X版的API非常相似,但是有一些重要的改变需要注意. 所有API接口函数和数据结构的前缀都由"sqlite_"改为了"sqlite3_". 这是为了避免同时使用SQLite 2.X和SQLite 3.0这两个版本的时候发生链接冲突.

由于对于C语言应该用什么数据类型来存放UTF-16编码的字符串并没有一致的规范. 因此SQLite使用了普通的void* 类型来指向UTF-16编码的字符串. 客户端使用过程中可以把void*映射成适合他们的系统的任何数据类型.

2.0 C/C++ 接口
SQLite 3.0一共有83个API函数,此外还有一些数据结构和预定义(#defines). (完整的API介绍请参看另一份文档.) 不过你们可以放心,这些接口使用起来不会像它的数量所暗示的那么复杂. 最简单的程序仍然使用三个函数就可以完成: sqlite3_open(), sqlite3_exec(), 和 sqlite3_close(). 要是想更好的控制数据库引擎的执行,可以使用提供的sqlite3_prepare()函数把SQL语句编译成字节码,然后在使用sqlite3_step()函数来执行编译后的字节码. 以sqlite3_column_开头的一组API函数用来获取查询结果集中的信息. 许多接口函数都是成对出现的,同时有UTF-8和UTF-16两个版本. 并且提供了一组函数用来执行用户自定义的SQL函数和文本排序函数.

2.1 如何打开关闭数据库
   typedef struct sqlite3 sqlite3;
   int sqlite3_open(const char*, sqlite3**);
   int sqlite3_open16(const void*, sqlite3**);
   int sqlite3_close(sqlite3*);
   const char *sqlite3_errmsg(sqlite3*);
   const void *sqlite3_errmsg16(sqlite3*);
   int sqlite3_errcode(sqlite3*);
sqlite3_open() 函数返回一个整数错误代码,而不是像第二版中一样返回一个指向sqlite3结构体的指针. sqlite3_open() 和 sqlite3_open16() 的不同之处在于sqlite3_open16() 使用UTF-16编码(使用本地主机字节顺序)传递数据库文件名. 如果要创建新数据库, sqlite3_open16() 将内部文本转换为UTF-16编码, 反之sqlite3_open() 将文本转换为UTF-8编码.

打开或者创建数据库的命令会被缓存,直到这个数据库真正被调用的时候才会被执行. 而且允许使用PRAGMA声明来设置如本地文本编码或默认内存页面大小等选项和参数.

sqlite3_errcode() 通常用来获取最近调用的API接口返回的错误代码. sqlite3_errmsg() 则用来得到这些错误代码所对应的文字说明. 这些错误信息将以 UTF-8 的编码返回,并且在下一次调用任何SQLite API函数的时候被清除. sqlite3_errmsg16() 和 sqlite3_errmsg() 大体上相同,除了返回的错误信息将以 UTF-16 本机字节顺序编码.

SQLite3的错误代码相比SQLite2没有任何的改变,它们分别是:

#define SQLITE_OK           0   /* Successful result */
#define SQLITE_ERROR        1   /* SQL error or missing database */
#define SQLITE_INTERNAL     2   /* An internal logic error in SQLite */
#define SQLITE_PERM         3   /* Access permission denied */
#define SQLITE_ABORT        4   /* Callback routine requested an abort */
#define SQLITE_BUSY         5   /* The database file is locked */
#define SQLITE_LOCKED       6   /* A table in the database is locked */
#define SQLITE_NOMEM        7   /* A malloc() failed */
#define SQLITE_READONLY     8   /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite_interrupt() */
#define SQLITE_IOERR       10   /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT     11   /* The database disk image is malformed */
#define SQLITE_NOTFOUND    12   /* (Internal Only) Table or record not found */
#define SQLITE_FULL        13   /* Insertion failed because database is full */
#define SQLITE_CANTOPEN    14   /* Unable to open the database file */
#define SQLITE_PROTOCOL    15   /* Database lock protocol error */
#define SQLITE_EMPTY       16   /* (Internal Only) Database table is empty */
#define SQLITE_SCHEMA      17   /* The database schema changed */
#define SQLITE_TOOBIG      18   /* Too much data for one row of a table */
#define SQLITE_CONSTRAINT  19   /* Abort due to contraint violation */
#define SQLITE_MISMATCH    20   /* Data type mismatch */
#define SQLITE_MISUSE      21   /* Library used incorrectly */
#define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
#define SQLITE_AUTH        23   /* Authorization denied */
#define SQLITE_ROW         100  /* sqlite_step() has another row ready */
#define SQLITE_DONE        101  /* sqlite_step() has finished executing */
2.2 执行 SQL 语句

       typedef int (*sqlite_callback)(void*,int,char**, char**); 
       int sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void*, char**);

sqlite3_exec 函数依然像它在SQLite2中一样承担着很多的工作. 该函数的第二个参数中可以编译和执行零个或多个SQL语句. 查询的结果返回给回调函数. 更多地信息可以查看API 参考.

在SQLite3里,sqlite3_exec一般是被准备SQL语句接口封装起来使用的.

       typedef struct sqlite3_stmt sqlite3_stmt; 
       int sqlite3_prepare(sqlite3*, const char*, int, sqlite3_stmt**, const char**); 
       int sqlite3_prepare16(sqlite3*, const void*, int, sqlite3_stmt**, const void**); 
       int sqlite3_finalize(sqlite3_stmt*); 
       int sqlite3_reset(sqlite3_stmt*);

sqlite3_prepare 接口把一条SQL语句编译成字节码留给后面的执行函数. 使用该接口访问数据库是当前比较好的的一种方法.

sqlite3_prepare() 处理的SQL语句应该是UTF-8编码的. 而sqlite3_prepare16() 则要求是UTF-16编码的. 输入的参数中只有第一个SQL语句会被编译. 第四个参数则用来指向输入参数中下一个需要编译的SQL语句存放的SQLite statement对象的指针, 任何时候如果调用 sqlite3_finalize() 将销毁一个准备好的SQL声明. 在数据库关闭之前,所有准备好的声明都必须被释放销毁. sqlite3_reset() 函数用来重置一个SQL声明的状态,使得它可以被再次执行.

SQL声明可以包含一些型如"?" 或 "?nnn" 或 ":aaa"的标记, 其中"nnn" 是一个整数,"aaa" 是一个字符串. 这些标记代表一些不确定的字符值(或者说是通配符),可以在后面用sqlite3_bind 接口来填充这些值. 每一个通配符都被分配了一个编号(由它在SQL声明中的位置决定,从1开始),此外也可以用 "nnn" 来表示 "?nnn" 这种情况. 允许相同的通配符在同一个SQL声明中出现多次, 在这种情况下所有相同的通配符都会被替换成相同的值. 没有被绑定的通配符将自动取NULL值.

       int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); 
       int sqlite3_bind_double(sqlite3_stmt*, int, double); 
       int sqlite3_bind_int(sqlite3_stmt*, int, int); 
       int sqlite3_bind_int64(sqlite3_stmt*, int, long long int); 
       int sqlite3_bind_null(sqlite3_stmt*, int); 
       int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); 
       int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); 
       int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);

以上是 sqlite3_bind 所包含的全部接口,它们是用来给SQL声明中的通配符赋值的. 没有绑定的通配符则被认为是空值. 绑定上的值不会被sqlite3_reset()函数重置. 但是在调用了sqlite3_reset()之后所有的通配符都可以被重新赋值.

在SQL声明准备好之后(其中绑定的步骤是可选的), 需要调用以下的方法来执行:

       int sqlite3_step(sqlite3_stmt*);

如果SQL返回了一个单行结果集,sqlite3_step() 函数将返回 SQLITE_ROW , 如果SQL语句执行成功或者正常将返回 SQLITE_DONE , 否则将返回错误代码. 如果不能打开数据库文件则会返回 SQLITE_BUSY . 如果函数的返回值是 SQLITE_ROW, 那么下边的这些方法可以用来获得记录集行中的数据:

       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); 
       int sqlite3_column_count(sqlite3_stmt*); 
       const char *sqlite3_column_decltype(sqlite3_stmt *, int iCol); 
       const void *sqlite3_column_decltype16(sqlite3_stmt *, int iCol); 
       double sqlite3_column_double(sqlite3_stmt*, int iCol); 
       int sqlite3_column_int(sqlite3_stmt*, int iCol); 
       long long int sqlite3_column_int64(sqlite3_stmt*, int iCol); 
       const char *sqlite3_column_name(sqlite3_stmt*, int iCol); 
       const void *sqlite3_column_name16(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_column_count()函数返回结果集中包含的列数. sqlite3_column_count() 可以在执行了 sqlite3_prepare()之后的任何时刻调用. sqlite3_data_count()除了必需要在sqlite3_step()之后调用之外,其他跟sqlite3_column_count() 大同小异. 如果调用sqlite3_step() 返回值是 SQLITE_DONE 或者一个错误代码, 则此时调用sqlite3_data_count() 将返回 0 ,然而 sqlite3_column_count() 仍然会返回结果集中包含的列数.

返回的记录集通过使用其它的几个 sqlite3_column_***() 函数来提取, 所有的这些函数都把列的编号作为第二个参数. 列编号从左到右以零起始. 请注意它和之前那些从1起始的参数的不同.

sqlite3_column_type()函数返回第N列的值的数据类型. 具体的返回值如下:

       #define SQLITE_INTEGER  1 
       #define SQLITE_FLOAT    2 
       #define SQLITE_TEXT     3 
       #define SQLITE_BLOB     4 
       #define SQLITE_NULL     5

sqlite3_column_decltype() 则用来返回该列在 CREATE TABLE 语句中声明的类型. 它可以用在当返回类型是空字符串的时候. sqlite3_column_name() 返回第N列的字段名. sqlite3_column_bytes() 用来返回 UTF-8 编码的BLOBs列的字节数或者TEXT字符串的字节数. sqlite3_column_bytes16() 对于BLOBs列返回同样的结果,但是对于TEXT字符串则按 UTF-16 的编码来计算字节数. sqlite3_column_blob() 返回 BLOB 数据. sqlite3_column_text() 返回 UTF-8 编码的 TEXT 数据. sqlite3_column_text16() 返回 UTF-16 编码的 TEXT 数据. sqlite3_column_int() 以本地主机的整数格式返回一个整数值. sqlite3_column_int64() 返回一个64位的整数. 最后, sqlite3_column_double() 返回浮点数.

不一定非要按照sqlite3_column_type()接口返回的数据类型来获取数据. 数据类型不同时软件将自动转换.

2.3 用户自定义函数 
可以使用以下的方法来创建用户自定义的SQL函数:

   typedef struct sqlite3_value sqlite3_value; 
   int sqlite3_create_function( 
     sqlite3 *, 
     const char *zFunctionName, 
     int nArg, 
     int eTextRep, 
     void*, 
     void (*xFunc)(sqlite3_context*,int,sqlite3_value**), 
     void (*xStep)(sqlite3_context*,int,sqlite3_value**), 
     void (*xFinal)(sqlite3_context*) 
   ); 
   int sqlite3_create_function16( 
     sqlite3*, 
     const void *zFunctionName, 
     int nArg, 
     int eTextRep, 
     void*, 
     void (*xFunc)(sqlite3_context*,int,sqlite3_value**), 
     void (*xStep)(sqlite3_context*,int,sqlite3_value**), 
     void (*xFinal)(sqlite3_context*) 
   ); 
   #define SQLITE_UTF8     1 
   #define SQLITE_UTF16    2 
   #define SQLITE_UTF16BE  3 
   #define SQLITE_UTF16LE  4 
   #define SQLITE_ANY      5

nArg 参数用来表明自定义函数的参数个数. 如果参数值为0,则表示接受任意个数的参数. 用 eTextRep 参数来表明传入参数的编码形式. 参数值可以是上面的五种预定义值. SQLite3 允许同一个自定义函数有多种不同的编码参数的版本. 数据库引擎会自动选择转换参数编码个数最少的版本使用.

普通的函数只需要设置 xFunc 参数,而把 xStep 和 xFinal 设为NULL. 聚合函数则需要设置 xStep 和 xFinal 参数,然后把 xFunc 设为NULL. 该方法和使用sqlite3_create_aggregate() API一样.

sqlite3_create_function16()和sqlite_create_function()的不同就在于自定义的函数名一个要求是 UTF-16 编码,而另一个则要求是 UTF-8.

请注意自定函数的参数目前使用了sqlite3_value结构体指针替代了SQLite version 2.X中的字符串指针. 下面的函数用来从sqlite3_value结构体中提取数据:

   const void *sqlite3_value_blob(sqlite3_value*); 
   int sqlite3_value_bytes(sqlite3_value*); 
   int sqlite3_value_bytes16(sqlite3_value*); 
   double sqlite3_value_double(sqlite3_value*); 
   int sqlite3_value_int(sqlite3_value*); 
   long long int sqlite3_value_int64(sqlite3_value*); 
   const unsigned char *sqlite3_value_text(sqlite3_value*); 
   const void *sqlite3_value_text16(sqlite3_value*); 
   int sqlite3_value_type(sqlite3_value*);

上面的函数调用以下的API来获得上下文内容和返回结果:

   void *sqlite3_aggregate_context(sqlite3_context*, int nbyte); 
   void *sqlite3_user_data(sqlite3_context*); 
   void sqlite3_result_blob(sqlite3_context*, const void*, int n, void(*)(void*)); 
   void sqlite3_result_double(sqlite3_context*, double); 
   void sqlite3_result_error(sqlite3_context*, const char*, int); 
   void sqlite3_result_error16(sqlite3_context*, const void*, int); 
   void sqlite3_result_int(sqlite3_context*, int); 
   void sqlite3_result_int64(sqlite3_context*, long long int); 
   void sqlite3_result_null(sqlite3_context*); 
   void sqlite3_result_text(sqlite3_context*, const char*, int n, void(*)(void*)); 
   void sqlite3_result_text16(sqlite3_context*, const void*, int n, void(*)(void*)); 
   void sqlite3_result_value(sqlite3_context*, sqlite3_value*); 
   void *sqlite3_get_auxdata(sqlite3_context*, int); 
   void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));

2.4 用户自定义排序规则 
下面的函数用来实现用户自定义的排序规则:

   sqlite3_create_collation(sqlite3*, const char *zName, int eTextRep, void*, 
      int(*xCompare)(void*,int,const void*,int,const void*)); 
   sqlite3_create_collation16(sqlite3*, const void *zName, int eTextRep, void*, 
      int(*xCompare)(void*,int,const void*,int,const void*)); 
   sqlite3_collation_needed(sqlite3*, void*, 
      void(*)(void*,sqlite3*,int eTextRep,const char*)); 
   sqlite3_collation_needed16(sqlite3*, void*, 
      void(*)(void*,sqlite3*,int eTextRep,const void*));

sqlite3_create_collation() 函数用来声明一个排序序列和实现它的比较函数. 比较函数只能用来做文本的比较. eTextRep 参数可以取如下的预定义值 SQLITE_UTF8, SQLITE_UTF16LE, SQLITE_UTF16BE, SQLITE_ANY,用来表示比较函数所处理的文本的编码方式. 同一个自定义的排序规则的同一个比较函数可以有 UTF-8, UTF-16LE 和 UTF-16BE 等多个编码的版本. sqlite3_create_collation16()和sqlite3_create_collation() 的区别也仅仅在于排序名称的编码是 UTF-16 还是 UTF-8.

可以使用 sqlite3_collation_needed() 函数来注册一个回调函数,当数据库引擎遇到未知的排序规则时会自动调用该函数. 在回调函数中可以查找一个相似的比较函数,并激活相应的sqlite_3_create_collation()函数. 回调函数的第四个参数是排序规则的名称,同样sqlite3_collation_needed采用 UTF-8 编码. sqlite3_collation_need16() 采用 UTF-16 编码.

-----------------------------------------------------

SQLite 不支持的 SQL 特性

    相对于试图列出 SQLite 支持的所有 SQL92 特性,只列出不支持的部分要简单得多。下面显示的就是 SQLite 所不支持的 SQL92 特性。

    这个列表的顺序关系到何时一个特性可能被加入到SQLite。接近列表顶部的特性更可能在不远的将来加入。接近列表底部的特性尚且没有直接的计划。

外键约束(FOREIGN KEY constraints)

外键约束会被解析但不会被执行。

完整的触发器支持(Complete trigger support)

现在有一些触发器的支持,但是还不完整。 缺少的特性包括 FOR EACH STATEMENT 触发器(现在所有的触发器都必须是 FOR EACH ROW ), 在表上的 INSTEAD OF 触发器(现在 INSTEAD OF 触发器只允许在视图上), 以及递归触发器——触发自身的触发器。

完整的 ALTER TABLE 支持(Complete ALTER TABLE support)

只支持 ALTER TABLE 命令的 RENAME TABLE 和 ADD COLUMN。 其他类型的 ALTER TABLE 操作如 DROP COLUMN,ALTER COLUMN,ADD CONSTRAINT 等等均被忽略。

嵌套事务(Nested transactions)

现在的实现只允许单一活动事务。

RIGHT 和 FULL OUTER JOIN(RIGHT and FULL OUTER JOIN)

LEFT OUTER JOIN 已经实现,但还没有 RIGHT OUTER JOIN 和 FULL OUTER JOIN。

可写视图(Writing to VIEWs)

SQLite 中的视图是只读的。无法在一个视图上执行 DELETE,INSERT,UPDATE。 不过你可以创建一个试图在视图上 DELETE,INSERT,UPDATE 时触发的触发器,然后在触发器中完成你所需要的工作。

GRANT 和 REVOKE(GRANT and REVOKE)

由于 SQLite 读和写的是一个普通的磁盘文件, 因此唯一可以获取的权限就是操作系统的标准的文件访问权限。 一般在客户机/服务器架构的关系型数据库系统上能找到的 GRANT 和 REVOKE 命令对于一个嵌入式的数据库引擎来说是没有意义的, 因此也就没有去实现。

-------------------------------

---------------------------------------------------------------------------------

SQLite第三版中的数据类型
1.存储类别
第二版把所有列的值都存储成ASCII文本格式。第三版则可以把数据存储成整数和实数,还可以存储BLOB数据.

Each value stored in an SQLite数据库中存储的每个值都有一个属性,都属于下面所列类中的一种,(被数据库引擎所控制)

空.这个值为空值

整数.值被标识为整数,依据值的大小可以依次被存储为1,2,3,4,5,6,7,8.

实数. 所有值都是浮动的数值,被存储为8字节的IEEE浮动标记序号.

文本. 值为文本字符串,使用数据库编码存储(TUTF-8, UTF-16BE or UTF-16-LE).

BLOB. 值是BLOB数据,如何输入就如何存储,不改变格式.

像SQLite2.0版一样,在3.0版中,除了INTEGER PRIMARY KEY,数据库中的任何列都可以存储任何类型的数据.这一规则也有例外,在下面的"严格相似模式"中将描述.

输入SQLite的所有值,不管它是嵌入 SQL语句中的文字还是提前编译好的绑定在SQL语句中的值,在SQL语句执行前都被存储为一个类.在下面所描述的情况下,数据库引擎将在执行时检查并把值在数字存储类(整数和实数)和文本类间转换.

存储的类别最初被分类为如下:

具体的值比如SQL语句部分的带双引号或单引号的文字被定义为文本,如果文字没带引号并没有小数点或指数则被定义为整数,如果文字没带引号但有小数点或指数则被定义为实数,如果值是空则被定义为空值.BLOB数据使用符号X'ABCD'来标识.

Values supplied using the 被输入的值使用sqlite3_bind_* APIs的被分类一个存储等级,这等级是和原来的类基本相一致的. (比如sqlite3_bind_blob()绑定一个BLOB的值).

值的分类是SQL分等级操作的结果,决定于最远的操作表达式.用户定义的功能也许会把值返回任意的类.在编译的时候来确定表达式的存储类基本是不可能的.


2. 列之间的亲和性
在SQLite3.0版中,值被定义为什么类型只和值自身有关,和列没有关系,和变量也没有关系. (这有时被称作

弱类型.)所有其它的我们所使用的数据库引擎都受静态类型系统的限制,其中的所有值的类是由其所属列的属性决定的,而和值无关.

为了最大限度的增加SQLite数据库和其他数据库的兼容性,SQLite支持列的"类型亲和性". 列的亲和性是为该列所存储的数据建议一个类型.我们要注意是建议而不是强迫.在理论上来讲,任何列依然是可以存储任何类型的数据的. 只是针对某些列,如果给建议类型的话,数据库将按所建议的类型存储.这个被优先使用的数据类型则被称为"亲和类型".

在SQLite3.0版中,数据库中的每一列都被定义为以下亲和类型中的一种:

文本 
数字的 
整数 
无 
一个具有类型亲和性的列按照无类型,文本,或BLOB存储所有的数据.如果数字数据被插入一个具有文本类型亲和性的列,在存储之前数字将被转换成文本.

一个具有数字类型亲和性的列也许使用所有的五个存储类型存储值.当文本数据被插入一个数字列时,在存储之前,数据库将尝试着把文本转换成整数或实数.如果能成功转换的话,值将按证书活实数的类型被存储. 如果不能 成功转换的话,值则只能按文本类型存储了,而不会被转换成无类型或BLOB类型来存储.

一个具有整数亲和力的列在转换方面和具有数字亲和力的列是一样的,但也有些区别 ,比如没有浮动量的实值(文本值转换的值)被插入具有整数亲和力的列时,它将被转换成整数并按整数类型存储.

一个具有无类型亲和力的列不会优先选择使用哪个类型.在数据被输入前它不会强迫数据转换类型.

2.1 列的亲和性的决定
一个列的亲和类型是由该列所宣称的类型决定的.遵守以下规则:

如果数据类型包括字符串"INT"那么它被定义成具有整数亲和性.

如果列中的数据类型包括以下任何的字符串 "CHAR", "CLOB", or "TEXT" 那么这个列则具有文本亲和性.要注意VARCHAR类型包括字符串"CHAR"因此也具有文本类型亲和性.

如果一个列的数据类型包括字符串"BLOB"或者如果数据类型被具体化了,那么这个列具有无类型亲和性.

否则就具有数字类型亲和性.

如果表格使用If "CREATE TABLE AS SELECT..."语句生成的,那么所有的列则都没有具体的数据类型,则没有类型亲和性.

2.2 列的亲和性的例子
CREATE TABLE t1(
    t  TEXT,
    nu NUMERIC, 
    i  INTEGER,
    no BLOB
);

-- Storage classes for the following row:
-- TEXT, REAL, INTEGER, TEXT
INSERT INTO t1 VALUES('500.0', '500.0', '500.0', '500.0');

-- Storage classes for the following row:
-- TEXT, REAL, INTEGER, REAL
INSERT INTO t1 VALUES(500.0, 500.0, 500.0, 500.0);
3.比较表达式
像SQLite2.0版一样,3.0版的一个特性是二进制比较符'=', '<', '<=', '>=' and '!=',一个操作'IN'可以测试固定的成员资格, 三重的比较操作符'BETWEEN'.

比较的结果决定于被比较的两个值的存储类型。遵循以下规则:

一个具有空存储类型的值被认为小于任何值(包括另外一个具有空存储类型的值)。

一个整数值或实数值小于任何文本值和BLOB值。 当一个整数或实数和另一个整数或实数相比较的时候,则按照实际数值来比较。

一个文本值小于BLOB值。当两个文本值相比较的时候,则用C语言类库中的memcmp()函数来比较。然而,有时候也不是这样的,比如在下面所描述的“用户定义的整理顺序”情况下。

当两个BLOB文本被比较的时候,结果决定于memcmp()函数。

在开始比较前,SQLite尝试着把值在数字存储级(整数和实数)和文本之间相互转换。下面列举了关于如何比较二进制值的例子。在着重号below中使用的表达式可以表示SQL标量表达式或是文本但不是一个列值。

当一个列值被比拟为表达式结果的时候,在比较开始前,列的亲和性将被应用在表达结果中。

当两个列值比较的时候,如果一个列有整数或数字亲和性的时候,而另外一列却没有,那么数字亲和性适用于从非数字列提取的任何具有文本存储类型的值. P>

当比较两个表达式的结果时,不发生任何转换,直接比较结果.如果一个字符串和一个数字比较, 数字总是小于字符串.

在SQLite中, 表达式"a BETWEEN b AND c"等于表达式 "a >= b AND a <= c",在比较表达式时,a可以是具有任何亲和性.

表达式 "a IN (SELECT b ....)" 在比较时遵循上面所提到的三条规则,是二进制比较.(例如, 在一个相似的样式 "a = b"). 例如,如果'b'是一个列值, 'a' 是一个表达式,那么,在开始比较前,'b'的亲和性就被转换为'a'的亲和性了.

SQLite把表达式 "a IN (x, y, z)" 和 "a = z OR a = y OR a = z"视为相等.

3.1 比较例子
CREATE TABLE t1(
    a TEXT,
    b NUMERIC,
    c BLOB
);

-- Storage classes for the following row:
-- TEXT, REAL, TEXT
INSERT INTO t1 VALUES('500', '500', '500');

-- 60 and 40 are converted to '60' and '40' and values are compared as TEXT.
SELECT a < 60, a < 40 FROM t1;
1|0

-- Comparisons are numeric. No conversions are required.
SELECT b < 60, b < 600 FROM t1;
0|1

-- Both 60 and 600 (storage class NUMERIC) are less than '500'
-- (storage class TEXT).
SELECT c < 60, c < 600 FROM t1;
0|0
4. 运算符
所有的数学运算符(所有的运算符而不是连锁作用标记符"||")运算对象首先具有数字亲和性, 如果一个或是两个都不能被转换为数字那么操作的结果将是空值。

对于连接作用操作符,所有操作符将首先具有文本亲和性。如果其中任何一个操作符不能被转换为文本(因为它是空值或是BLOB)连接作用操作符将是空值。

5. 分类,排序,混合挑选
当用子句ORDER挑选值时,空值首先被挑选出来, 然后是整数和实数按顺序被挑选出来, 然后是文本值按memcmp()顺序被挑选出来, 最后是BLOB值按memcmp()顺序被挑选出来.在挑选之前, 没有存储类型的值都被转换了.

When grouping values with the 当用GROUP BY子句给值分组时,具有不同存储类型的值被认为是不同的, 但也有例外, 比如,一个整数值和一个实数值从数字角度来说是相等的,那么它们则是相等的.用GROUP by 子句比较完后,值不具有任何亲和性.

混合挑选操作符UNION, INTERSECT and EXCEPT 在值之间实行绝对的比较,同样的亲和性将被应用于所有的值,这些值将被存储在一个单独的具有混合SELECT的结果组的列中. 被赋予的亲和性是该列的亲和性,这个亲和性是由剩下的大部分的混合SELECTS返回的,这些混合SELECTS在那个位置上有列值(而不是其它类型的表达式). 如果一个给定的混合SELECT列没有SELECTS的量, 那么在比较前,该列的值将不具有任何亲和性.

6. 其它亲和性模式
以上的部分所描述的都是数据库引擎在正常亲和性模式下所进行的操作, SQLite将描述其它两种亲和性模式,如下:

严格亲和性模式.在这种模式下,如果需要值之间相互转换数据存储类型的话,数据库引擎将发送错误报告,当前语句也将会重新运行.

无亲和性模式.在这种模式下,值的数据存储类型不发生转换.具有不同存储类型的值之间不能比较,但整数和实数之间可以比较.

7.用户定义的校对顺序
By default, when 当SQLite比较两个文本值的时候,通过系统设定,不管字符串的编码是什么,用memcmp()来比较. SQLite第三版允许用户提供任意的函数来代替memcmp(),也就是用户定义的比较顺序.

除了系统预设的BINARY比较顺序,它是用memcmp()函数比较,SQLite还包含了两个额外的内置比较顺序函数, NOCASE和REVERSE:

BINARY -使用memcmp()比较字符串数据, 不考虑文本编码. 
REVERSE -用倒序比较二进制文本. 
NOCASE - 和二进制一样,但在比较之前,26位的大写字母盘要被折合成相应的小写字母盘. 
7.1 分配比较顺序
每个表格中的每个列都有一个预设的比较类型.如果一个比较类型不是二进制所要求的,比较的子句将被具体化为 列的定义 来定义该列.

当用SQLite比较两个文本值时,比较顺序将按照以下的规则来决定比较的结果.文档的第三部分和第五部分描述在何种场合下发生这种比较.

对于二进制比较符(=, <, >, <= and >=),如果每个操作数是一列的话,那么该列的默认比较类型决定于所使用的比较顺序. 如果两个操作数都是列的话,那么左边的操作数的比较类型决定了所要使用的比较顺序.如果两个操作数都不是一列,将使用二进制来比较.

表达式"x BETWEEN y and z"和 "x >= y AND x <= z"是相同的. 表达式"x IN (SELECT y ...)" 和表达式 "x = y" 使用同样的方法来操作,这是为了决定所要使用的比较顺序.如果X是一列或者二进制的,则"x IN (y, z ...)" 形式的表达式所使用的比较顺序是X的默认的比较类型.

ORDER BY clause that is part of a SELECT statement may be assigned a collation sequence to be used for the sort operation explicitly. In this case the explicit collation sequence is always used. Otherwise, if the expression sorted by an ORDER BY clause is a column, then the default collation type of the column is used to determine sort order. If the expression is not a column, then the BINARY collation sequence is used.

7.2 比较顺序的例子
下面的例子介绍了The examples below identify the collation sequences that would be used to determine the results of text comparisons that may be performed by various SQL statements. Note that a text comparison may not be required, and no collation sequence used, in the case of numeric, blob or NULL values.

CREATE TABLE t1(
    a,                 -- default collation type BINARY
    b COLLATE BINARY,  -- default collation type BINARY
    c COLLATE REVERSE, -- default collation type REVERSE
    d COLLATE NOCASE   -- default collation type NOCASE
);

-- Text comparison is performed using the BINARY collation sequence.
SELECT (a = b) FROM t1;

-- Text comparison is performed using the NOCASE collation sequence.
SELECT (d = a) FROM t1;

-- Text comparison is performed using the BINARY collation sequence.
SELECT (a = d) FROM t1;

-- Text comparison is performed using the REVERSE collation sequence.
SELECT ('abc' = c) FROM t1;

-- Text comparison is performed using the REVERSE collation sequence.
SELECT (c = 'abc') FROM t1;

-- Grouping is performed using the NOCASE collation sequence (i.e. values
-- 'abc' and 'ABC' are placed in the same group).
SELECT count(*) GROUP BY d FROM t1;

-- Grouping is performed using the BINARY collation sequence.
SELECT count(*) GROUP BY (d || '') FROM t1;

-- Sorting is performed using the REVERSE collation sequence.
SELECT * FROM t1 ORDER BY c;

-- Sorting is performed using the BINARY collation sequence.
SELECT * FROM t1 ORDER BY (c || '');

-- Sorting is performed using the NOCASE collation sequence.
SELECT * FROM t1 ORDER BY c COLLATE NOCASE;
----------------------------------------------------------------


Sqlite3 的确很好用。小巧、速度快。但是因为非微软的产品,帮助文档总觉得不够。这些天再次研究它,又有一些收获,这里把我对 sqlite3 的研究列出来,以备忘记。这里要注明,我是一个跨平台专注者,并不喜欢只用 windows 平台。我以前的工作就是为 unix 平台写代码。下面我所写的东西,虽然没有验证,但是我已尽量不使用任何 windows 的东西,只使用标准 C 或标准C++。但是,我没有尝试过在别的系统、别的编译器下编译,因此下面的叙述如果不正确,则留待以后修改。下面我的代码仍然用 VC 编写,因为我觉得VC是一个很不错的IDE,可以加快代码编写速度(例如配合 Vassist )。下面我所说的编译环境,是VC2003。如果读者觉得自己习惯于 unix 下用 vi 编写代码速度较快,可以不用管我的说明,只需要符合自己习惯即可,因为我用的是标准 C 或 C++ 。不会给任何人带来不便。一、         版本从http://www.sqlite.org/网站可下载到最新的 sqlite 代码和编译版本。我写此文章时,最新代码是 3.3.17 版本。很久没有去下载 sqlite 新代码,因此也不知道 sqlite 变化这么大。以前很多文件,现在全部合并成一个 sqlite3.c 文件。如果单独用此文件,是挺好的,省去拷贝一堆文件还担心有没有遗漏。但是也带来一个问题:此文件太大,快接近7万行代码,VC开它整个机器都慢下来了。如果不需要改它代码,也就不需要打开 sqlite3.c 文件,机器不会慢。但是,下面我要写通过修改 sqlite 代码完成加密功能,那时候就比较痛苦了。如果个人水平较高,建议用些简单的编辑器来编辑,例如 UltraEdit 或 Notepad 。速度会快很多。二、         基本编译这个不想多说了,在 VC 里新建 dos 控制台空白工程,把 sqlite3.c 和 sqlite3.h 添加到工程,再新建一个 main.cpp 文件。在里面写:extern "C"
{
#include "./sqlite3.h"
};int main( int , char** )
{
return 0;
}为什么要 extern “C” ?如果问这个问题,我不想说太多,这是C++的基础。要在 C++ 里使用一段 C 的代码,必须要用 extern “C” 括起来。C++跟 C虽然语法上有重叠,但是它们是两个不同的东西,内存里的布局是完全不同的,在C++编译器里不用extern “C”括起C代码,会导致编译器不知道该如何为 C 代码描述内存布局。可能在 sqlite3.c 里人家已经把整段代码都 extern “C” 括起来了,但是你遇到一个 .c 文件就自觉的再括一次,也没什么不好。
基本工程就这样建立起来了。编译,可以通过。但是有一堆的 warning。可以不管它。三、         SQLITE操作入门sqlite提供的是一些C函数接口,你可以用这些函数操作数据库。通过使用这些接口,传递一些标准 sql 语句(以 char * 类型)给 sqlite 函数,sqlite 就会为你操作数据库。sqlite 跟MS的access一样是文件型数据库,就是说,一个数据库就是一个文件,此数据库里可以建立很多的表,可以建立索引、触发器等等,但是,它实际上得到的就是一个文件。备份这个文件就备份了整个数据库。sqlite 不需要任何数据库引擎,这意味着如果你需要 sqlite 来保存一些用户数据,甚至都不需要安装数据库(如果你做个小软件还要求人家必须装了sqlserver 才能运行,那也太黑心了)。下面开始介绍数据库基本操作。
(1)     基本流程i.1              关键数据结构sqlite 里最常用到的是 sqlite3 * 类型。从数据库打开开始,sqlite就要为这个类型准备好内存,直到数据库关闭,整个过程都需要用到这个类型。当数据库打开时开始,这个类型的变量就代表了你要操作的数据库。下面再详细介绍。i.2              打开数据库int sqlite3_open( 文件名, sqlite3 ** );用这个函数开始数据库操作。需要传入两个参数,一是数据库文件名,比如:c:\\DongChunGuang_Database.db。文件名不需要一定存在,如果此文件不存在,sqlite 会自动建立它。如果它存在,就尝试把它当数据库文件来打开。sqlite3 ** 参数即前面提到的关键数据结构。这个结构底层细节如何,你不要关它。函数返回值表示操作是否正确,如果是 SQLITE_OK 则表示操作正常。相关的返回值sqlite定义了一些宏。具体这些宏的含义可以参考 sqlite3.h 文件。里面有详细定义(顺便说一下,sqlite3 的代码注释率自称是非常高的,实际上也的确很高。只要你会看英文,sqlite 可以让你学到不少东西)。下面介绍关闭数据库后,再给一段参考代码。i.3              关闭数据库int sqlite3_close(sqlite3 *);         前面如果用 sqlite3_open 开启了一个数据库,结尾时不要忘了用这个函数关闭数据库。下面给段简单的代码:extern "C"
{
#include "./sqlite3.h"
};int main( int , char** )
{
      sqlite3 * db = NULL; //声明sqlite关键结构指针
      int result;//打开数据库//需要传入 db 这个指针的指针,因为 sqlite3_open 函数要为这个指针分配内存,还要让db指针指向这个内存区      result = sqlite3_open( “c:\\Dcg_database.db”, &db );
      if( result != SQLITE_OK )
      {
       //数据库打开失败
return -1;
}
//数据库操作代码
//数据库打开成功
//关闭数据库
sqlite3_close( db );return 0;
}这就是一次数据库操作过程。
(2)                SQL语句操作本节介绍如何用sqlite 执行标准 sql 语法。
i.1              执行sql语句int sqlite3_exec(sqlite3*, const char *sql, sqlite3_callback, void *, char **errmsg );这就是执行一条 sql 语句的函数。第1个参数不再说了,是前面open函数得到的指针。说了是关键数据结构。第2个参数const char *sql 是一条 sql 语句,以\0结尾。第3个参数sqlite3_callback 是回调,当这条语句执行之后,sqlite3会去调用你提供的这个函数。(什么是回调函数,自己找别的资料学习)第4个参数void *                   是你所提供的指针,你可以传递任何一个指针参数到这里,这个参数最终会传到回调函数里面,如果不需要传递指针给回调函数,可以填NULL。等下我们再看回调函数的写法,以及这个参数的使用。第5个参数char ** errmsg 是错误信息。注意是指针的指针。sqlite3里面有很多固定的错误信息。执行 sqlite3_exec 之后,执行失败时可以查阅这个指针(直接 printf(“%s\n”,errmsg))得到一串字符串信息,这串信息告诉你错在什么地方。sqlite3_exec函数通过修改你传入的指针的指针,把你提供的指针指向错误提示信息,这样sqlite3_exec函数外面就可以通过这个 char*得到具体错误提示。说明:通常,sqlite3_callback 和它后面的 void * 这两个位置都可以填 NULL。填NULL表示你不需要回调。比如你做 insert 操作,做 delete 操作,就没有必要使用回调。而当你做 select 时,就要使用回调,因为 sqlite3 把数据查出来,得通过回调告诉你查出了什么数据。
i.2              exec 的回调typedef int (*sqlite3_callback)(void*,int,char**, char**);你的回调函数必须定义成上面这个函数的类型。下面给个简单的例子://sqlite3的回调函数       // sqlite 每查到一条记录,就调用一次这个回调
int LoadMyInfo( void * para, int n_column, char ** column_value, char ** column_name )
{
            //para是你在 sqlite3_exec 里传入的 void * 参数            //通过para参数,你可以传入一些特殊的指针(比如类指针、结构指针),然后在这里面强制转换成对应的类型(这里面是void*类型,必须强制转换成你的类型才可用)。然后操作这些数据            //n_column是这一条记录有多少个字段 (即这条记录有多少列)            // char ** column_value 是个关键值,查出来的数据都保存在这里,它实际上是个1维数组(不要以为是2维数组),每一个元素都是一个 char * 值,是一个字段内容(用字符串来表示,以\0结尾)            //char ** column_name 跟 column_value是对应的,表示这个字段的字段名称
       
            //这里,我不使用 para 参数。忽略它的存在.            int i;printf( “记录包含 %d 个字段\n”, n_column );for( i = 0 ; i < n_column; i ++ )
{
       printf( “字段名:%s ?> 字段值:%s\n”, column_name[i], column_value[i] );
}printf( “------------------\n“ );       return 0;
}
int main( int , char ** )
{
            sqlite3 * db;
            int result;
            char * errmsg = NULL;            result = sqlite3_open( “c:\\Dcg_database.db”, &db );
      if( result != SQLITE_OK )
      {
       //数据库打开失败
return -1;
}//数据库操作代码
//创建一个测试表,表名叫 MyTable_1,有2个字段: ID 和 name。其中ID是一个自动增加的类型,以后insert时可以不去指定这个字段,它会自己从0开始增加
result = sqlite3_exec( db, “create table MyTable_1( ID integer primary key autoincrement, name nvarchar(32) )”, NULL, NULL, errmsg );
if(result != SQLITE_OK )
{
       printf( “创建表失败,错误码:%d,错误原因:%s\n”, result, errmsg );
}
//插入一些记录
result = sqlite3_exec( db, “insert into MyTable_1( name ) values ( ‘走路’ )”, 0, 0, errmsg );
if(result != SQLITE_OK )
{
       printf( “插入记录失败,错误码:%d,错误原因:%s\n”, result, errmsg );
}//开始查询数据库result = sqlite3_exec( db, “select * from MyTable_1”, LoadMyInfo, NULL, errmsg );//关闭数据库sqlite3_close( db );return 0;
}
通过上面的例子,应该可以知道如何打开一个数据库,如何做数据库基本操作。有这些知识,基本上可以应付很多数据库操作了。i.3              不使用回调查询数据库上面介绍的 sqlite3_exec 是使用回调来执行 select 操作。还有一个方法可以直接查询而不需要回调。但是,我个人感觉还是回调好,因为代码可以更加整齐,只不过用回调很麻烦,你得声明一个函数,如果这个函数是类成员函数,你还不得不把它声明成 static 的(要问为什么?这又是C++基础了。C++成员函数实际上隐藏了一个参数:this,C++调用类的成员函数的时候,隐含把类指针当成函数的第一个参数传递进去。结果,这造成跟前面说的 sqlite 回调函数的参数不相符。只有当把成员函数声明成 static 时,它才没有多余的隐含的this参数)。虽然回调显得代码整齐,但有时候你还是想要非回调的 select 查询。这可以通过 sqlite3_get_table 函数做到。int sqlite3_get_table(sqlite3*, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg );第1个参数不再多说,看前面的例子。第2个参数是 sql 语句,跟 sqlite3_exec 里的 sql 是一样的。是一个很普通的以\0结尾的char *字符串。第3个参数是查询结果,它依然一维数组(不要以为是二维数组,更不要以为是三维数组)。它内存布局是:第一行是字段名称,后面是紧接着是每个字段的值。下面用例子来说事。第4个参数是查询出多少条记录(即查出多少行)。第5个参数是多少个字段(多少列)。第6个参数是错误信息,跟前面一样,这里不多说了。下面给个简单例子:int main( int , char ** )
{
            sqlite3 * db;
            int result;
            char * errmsg = NULL;      char **dbResult; //是 char ** 类型,两个*号            int nRow, nColumn;            int i , j;            int index;            result = sqlite3_open( “c:\\Dcg_database.db”, &db );
      if( result != SQLITE_OK )
      {
       //数据库打开失败
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 的常用用法都介绍完了。用以上的方法,再配上 sql 语句,完全可以应付绝大多数数据库需求。但有一种情况,用上面方法是无法实现的:需要insert、select 二进制。当需要处理二进制数据时,上面的方法就没办法做到。下面这一节说明如何插入二进制数据
(2)                操作二进制sqlite 操作二进制数据需要用一个辅助的数据类型:sqlite3_stmt * 。这个数据类型记录了一个“sql语句”。为什么我把 “sql语句” 用双引号引起来?因为你可以把 sqlite3_stmt * 所表示的内容看成是 sql语句,但是实际上它不是我们所熟知的sql语句。它是一个已经把sql语句解析了的、用sqlite自己标记记录的内部数据结构。正因为这个结构已经被解析了,所以你可以往这个语句里插入二进制数据。当然,把二进制数据插到 sqlite3_stmt 结构里可不能直接 memcpy ,也不能像 std::string 那样用 + 号。必须用 sqlite 提供的函数来插入。
i.1            写入二进制下面说写二进制的步骤。要插入二进制,前提是这个表的字段的类型是 blob 类型。我假设有这么一张表:create table Tbl_2( ID integer, file_content blob )首先声明sqlite3_stmt * stat;然后,把一个 sql 语句解析到 stat 结构里去:sqlite3_prepare( db, “insert into Tbl_2( ID, file_content) values( 10, ? )”, -1, &stat, 0 );上面的函数完成 sql 语句的解析。第一个参数跟前面一样,是个 sqlite3 * 类型变量,第二个参数是一个 sql 语句。这个 sql 语句特别之处在于 values 里面有个 ? 号。在sqlite3_prepare函数里,?号表示一个未定的值,它的值等下才插入。第三个参数我写的是-1,这个参数含义是前面 sql 语句的长度。如果小于0,sqlite会自动计算它的长度(把sql语句当成以\0结尾的字符串)。第四个参数是 sqlite3_stmt 的指针的指针。解析以后的sql语句就放在这个结构里。第五个参数我也不知道是干什么的。为0就可以了。如果这个函数执行成功(返回值是 SQLITE_OK 且 stat 不为NULL ),那么下面就可以开始插入二进制数据。sqlite3_bind_blob( stat, 1, pdata, (int)(length_of_data_in_bytes), NULL ); // pdata为数据缓冲区,length_of_data_in_bytes为数据大小,以字节为单位这个函数一共有5个参数。第1个参数:是前面prepare得到的 sqlite3_stmt * 类型变量。第2个参数:?号的索引。前面prepare的sql语句里有一个?号,假如有多个?号怎么插入?方法就是改变 bind_blob 函数第2个参数。这个参数我写1,表示这里插入的值要替换 stat 的第一个?号(这里的索引从1开始计数,而非从0开始)。如果你有多个?号,就写多个 bind_blob 语句,并改变它们的第2个参数就替换到不同的?号。如果有?号没有替换,sqlite为它取值null。第3个参数:二进制数据起始指针。第4个参数:二进制数据的长度,以字节为单位。第5个参数:是个析够回调函数,告诉sqlite当把数据处理完后调用此函数来析够你的数据。这个参数我还没有使用过,因此理解也不深刻。但是一般都填NULL,需要释放的内存自己用代码来释放。bind完了之后,二进制数据就进入了你的“sql语句”里了。你现在可以把它保存到数据库里:int result = sqlite3_step( stat );通过这个语句,stat 表示的sql语句就被写到了数据库里。最后,要把 sqlite3_stmt 结构给释放:sqlite3_finalize( stat ); //把刚才分配的内容析构掉 i.2            读出二进制下面说读二进制的步骤。跟前面一样,先声明 sqlite3_stmt * 类型变量:sqlite3_stmt * stat;然后,把一个 sql 语句解析到 stat 结构里去:sqlite3_prepare( db, “select * from Tbl_2”, -1, &stat, 0 );当 prepare 成功之后(返回值是 SQLITE_OK ),开始查询数据。int result = sqlite3_step( stat );这一句的返回值是 SQLITE_ROW 时表示成功(不是 SQLITE_OK )。你可以循环执行 sqlite3_step 函数,一次 step 查询出一条记录。直到返回值不为 SQLITE_ROW 时表示查询结束。然后开始获取第一个字段:ID 的值。ID是个整数,用下面这个语句获取它的值:int id = sqlite3_column_int( stat, 0 ); //第2个参数表示获取第几个字段内容,从0开始计算,因为我的表的ID字段是第一个字段,因此这里我填0 下面开始获取 file_content 的值,因为 file_content 是二进制,因此我需要得到它的指针,还有它的长度:           const void * pFileContent = sqlite3_column_blob( stat, 1 );           int len = sqlite3_column_bytes( stat, 1 );这样就得到了二进制的值。把 pFileContent 的内容保存出来之后,不要忘了释放 sqlite3_stmt 结构:sqlite3_finalize( stat ); //把刚才分配的内容析构掉 i.3            重复使用 sqlite3_stmt 结构如果你需要重复使用 sqlite3_prepare 解析好的 sqlite3_stmt 结构,需要用函数: sqlite3_reset。result = sqlite3_reset(stat);这样, stat 结构又成为 sqlite3_prepare 完成时的状态,你可以重新为它 bind 内容。
(4)                事务处理sqlite 是支持事务处理的。如果你知道你要同步删除很多数据,不仿把它们做成一个统一的事务。通常一次 sqlite3_exec 就是一次事务,如果你要删除1万条数据,sqlite就做了1万次:开始新事务->删除一条数据->提交事务->开始新事务->… 的过程。这个操作是很慢的。因为时间都花在了开始事务、提交事务上。你可以把这些同类操作做成一个事务,这样如果操作错误,还能够回滚事务。事务的操作没有特别的接口函数,它就是一个普通的 sql 语句而已:分别如下:int result;result = sqlite3_exec( db, "begin transaction", 0, 0, &zErrorMsg ); //开始一个事务result = sqlite3_exec( db, "commit transaction", 0, 0, &zErrorMsg ); //提交事务result = sqlite3_exec( db, "rollback transaction", 0, 0, &zErrorMsg ); //回滚事务

 

----------------------------------------------------------
#include <stdio.h>
02  #include <sqlite3.h>
03  
04  static int callback(void *NotUsed, int argc, char **argv, char **azColName){
05    int i;
06    for(i=0; i<argc; i++){
07      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
08    }
09    printf("\n");
10    return 0;
11  }
12  
13  int main(int argc, char **argv){
14    sqlite3 *db;
15    char *zErrMsg = 0;
16    int rc;
17  
18    if( argc!=3 ){
19      fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]);
20      exit(1);
21    }
22    rc = sqlite3_open(argv[1], &db);
23    if( rc ){
24      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
25      sqlite3_close(db);
26      exit(1);
27    }
28    rc = sqlite3_exec(db, argv[2], callback, 0, &zErrMsg);
29    if( rc!=SQLITE_OK ){
30      fprintf(stderr, "SQL error: %s\n", zErrMsg);
31      sqlite3_free(zErrMsg);
32    }
33    sqlite3_close(db);
34    return 0;
35  }

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值