sqlite3学习

  • 基本API和过程:

参考: http://www.blogjava.net/xylz/archive/2012/09/25/388519.html\

官网:http://www.sqlite.org/cintro.html

http://www.cnblogs.com/stephen-liu74/archive/2012/03/05/2340780.html

http://www.cnblogs.com/nbsofer/archive/2012/05/02/2479168.html

http://www.cnblogs.com/memset/archive/2012/05/02/2479156.html

例子程序:

#include <stdio.h>
#include <assert.h>
#include <sqlite3.h>

int main()
{
    int ret;
    sqlite3* pDb = NULL;
    char* pErrMsg = NULL;
    printf("Open db\n");
    ret = sqlite3_open("./my.db", &pDb);//Open the db file
    assert(SQLITE_OK == ret);

    printf("Clear data\n");
    sqlite3_exec(pDb, "drop table if exists myTable\n", NULL, NULL, NULL);
    
    printf("Create table\n");
    ret = sqlite3_exec(pDb, "create table if not exists myTable(id integer primary key, name text)", NULL, NULL, &pErrMsg);//Create a table
    if (SQLITE_OK != ret) printf("%s\n", pErrMsg);
    assert(SQLITE_OK == ret);
    sqlite3_free(pErrMsg);//TODO:ÊÇ·ñҪÿ´Îsqlite3_exec¶¼free¶ø²»ÊÇÖ»freeÒ»´Î?
    
    printf("Insert some lines\n");
    ret = sqlite3_exec(pDb, "insert into myTable(id,name) values(2,'2222222')", NULL, NULL, &pErrMsg);
    ret = sqlite3_exec(pDb, "insert into myTable(id,name) values(3,'3333333')", NULL, NULL, &pErrMsg);
    ret = sqlite3_exec(pDb, "insert into myTable(id,name) values(11,'11111')", NULL, NULL, &pErrMsg);
    //if (SQLITE_OK != ret) printf("%s\n", pErrMsg);
    assert(SQLITE_OK == ret);
    
    printf("Insert a line that contained ' \n");
    char* sql = sqlite3_mprintf("insert into myTable(id,name) values(14,'%q')", "luo'jiao");
    printf("sql: %s\n", sql);
    ret = sqlite3_exec(pDb, sql, NULL, NULL, NULL);
    assert(SQLITE_OK == ret);
    sqlite3_free(sql);
    
    printf("Delete some lines\n");
    //ret = sqlite3_exec(pDb, "delete from myTable where id < 10", NULL, NULL, &pErrMsg);

    printf("Use prepare&step to insert a line\n");
    sqlite3_stmt *stmt;
    ret = sqlite3_prepare_v2(pDb, "insert into myTable(id,name) values(?,?)", -1, &stmt, NULL);
    assert(SQLITE_OK == ret);
    for (int i = 30; i < 33; i++)
    {
        sqlite3_bind_int(stmt, 1, i);
        char text[50] = {0};
        sprintf(text, "prepare line id%d", i);
        sqlite3_bind_text(stmt, 2, text, -1, NULL);
        sqlite3_step(stmt);
        sqlite3_reset(stmt);
    }
    sqlite3_finalize(stmt);
    assert(SQLITE_OK == ret);

    printf("Select some data from table, result:\n");
    sqlite3_stmt *stmt1;
    const char* sql1 = "select * from myTable where id > 10";
    printf("Sql: select * from myTable where id > 10\nid  name\n");
    ret = sqlite3_prepare_v2(pDb, sql1, -1, &stmt1, NULL);
    assert(SQLITE_OK == ret);
    while (SQLITE_ROW == sqlite3_step(stmt1))
    {
        int id = sqlite3_column_int(stmt1, 0);
        const unsigned char* pName = sqlite3_column_text(stmt1, 1);
        printf("%-4d%s\n", id, pName);
    }
    ret = sqlite3_finalize(stmt1);
    assert(SQLITE_OK == ret);

    sqlite3_close(pDb);
    return 0;
}

  • 基本SQL语句

更新:UPDATE myTable SET address = 'Nanjing', name = 'luojiao'WHEREid = 1;

复合插入:

INSERT OR REPLACE:如果不存在就插入,存在就更新
INSERT OR IGNORE:如果不存在就插入,存在就忽略

模糊匹配:用like替代等号并使用通配符%,例如: select * from mytable where id like '1111%';  select * from mytable where name like 'line%';

like 使用%代表任何字符
like 使用?代表单个字符
matches使用*代表任何字符
matches使用_代表单个字符
例如:
select * from t_test where name matches "*"

  • 根据表创建新表

举例:

CREATE TABLE newTable AS SELECT id, name FROM existedTable WHERE id < 10;

  • 触发器(Trigger):

参考http://blog.csdn.net/dliyuedong/article/details/40565407

CREATE TRIGGER < [ BEFORE | AFTER ] > < [ INSERT | UPDATE | DELETE ] >
ON <tableName>
FOR EACH ROW //可选,不写也一样
BEGIN
--do something; //记得句末一定要加分号
END ;

例如:

CREATE TRIGGER myTrigger1 after delete on myTable

BEGIN

    delete from relatedTable where relatedTable.id = old.id;

END;

其中前面作用表的新旧数据使用new和old进行指向,例如insert时new指向插入的行数据,delete时old指向删除的行数据,update时类推。

注意:sqlite3的触发器语法跟SqlServer等大型数据库不太一样,参照SqlServer的方式来写会无法执行,例如不需要关键字as,也不能用关键字for(只能用before/after),一定要有begin/end,一定要do something语句后加分号

  • 虚拟表virtual table

参考官网:http://www.sqlite.org/vtab.html

create/drop table时,调用xCreate/xConnect和xDestroy/xDisconnect,在这四个函数里实现表的创建销毁。

select时,xBestIndex、xOpen、xFilter、xEof、xColumn、xRowid、xNext、xClose配合使用,调用顺序就是我列的顺序。

xBestIndex 用来处理SQL语句中的WHERE/GROUP BY/ORDER BY这样的约束条件的。入参是sqlite3_index_info中的 /* Inputs */ 部分,出参是sqlite3_index_info中的 /* Outputs */ 部分。每一个WHERE约束条件对应一个aConstraint结构,每一个ORDER  BY等对应一个aOrderBy结构。

解析完成后,如果希望哪个约束条件aConstraint[i]被传递到XFilter的argv[n],那就填写aConstraintUsage[i].argvIndex = n;

idxNum和idxStr的含义自己定义,会传给xFilter,含义由使用者自定,比较灵活

XFilter 用来进行行选择,根据xBestIndex传过来的条件,选出符合条件的行。

例子代码: 每次执行前要把my.db或里面的virTable表删除,否则会创建失败。加了if not exists会失败。

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sqlite3.h>
//#include <sqlite3ext.h>

/************************* VT的数据库表信息 *************************/
/*这里建一个最简单的数据库table: 
vtable(id int, name text)
       1,      aaa
       2,      bbb
       3,      ccc
       4,      ddd
       5,      eee
*/
const int DATA_COUNT = 5;//table大小即行数
static int gIDinTable[DATA_COUNT] = {1,2,3,4,5};//table中的id列数据
const int NAME_LENGTH = 10;
static char gNameinTable[DATA_COUNT][NAME_LENGTH] = {"aaa","bbb","ccc","ddd","eee"};//table中的name列数据
static int curPos = 0;//当前cursor
/************************* VT的数据库表信息 *************************/

static int MyDestructor(sqlite3_vtab *pVtab) // finished: 100%
{
    printf("MyDestructor\n");
    return SQLITE_OK;
}

static int MyCreate( sqlite3 *db, void *p_aux, int argc, const char * const* argv , sqlite3_vtab **pp_vt,   char **pzErr ) // finished: 100%
{
    printf("MyCreate\n");
    int ret = sqlite3_declare_vtab(db, "create table vtable(id int, name text)");
    if (SQLITE_OK != ret)
    {
        return SQLITE_ERROR;
    }
    sqlite3_vtab* pVtab = (sqlite3_vtab*)sqlite3_malloc(sizeof(sqlite3_vtab));
    *pp_vt = (sqlite3_vtab *)pVtab;
    return SQLITE_OK;
}

static int MyConnect( sqlite3 *db, void *p_aux, int argc, const char * const *argv, sqlite3_vtab **pp_vt, char **pzErr ) // finished: 100%
{
    printf("MyConnect\n");
    return MyCreate(db, p_aux, argc, argv, pp_vt, pzErr);
    return SQLITE_OK;
}

static int MyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) // finished: 100%
{
    printf("MyBestIndex\n");
    //TODO: 这里的aConstraintUsage是谁申请的内存? 应该是只有select语句有条件约束这个就自动申请了?需要看下
    //pIdxInfo->aConstraintUsage[0].argvIndex = 1;
    return SQLITE_OK;
}

static int MyDisconnect(sqlite3_vtab *pVtab) // finished: 100%
{
    printf("MyDisconnect\n");
    sqlite3_free(pVtab);
    return SQLITE_OK;
}

static int MyDestroy(sqlite3_vtab *pVtab) // finished: 100%
{
    printf("MyDestroy\n");

    return MyDisconnect(pVtab);;
}

static int MyOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **pp_cursor) // finished: 100%
{
    printf("MyOpen\n");
    sqlite3_vtab_cursor* pCursor = (sqlite3_vtab_cursor*)sqlite3_malloc(sizeof(sqlite3_vtab_cursor));
    if (pCursor == NULL)
    {
        return SQLITE_NOMEM;
    }
    *pp_cursor = pCursor;
    //严格来说,这里应该扩展sqlite3_vtab_cursor来包含curPos,作为cursor的记录。例子就从简了,用全局变量
    curPos = 0;//Open时把cursor初始化
    
    return SQLITE_OK;
}

static int MyClose(sqlite3_vtab_cursor *cur) // finished: 100%
{
    printf("MyClose\n");
    if (cur)
    {
        sqlite3_free(cur);
    }
    return SQLITE_OK;
}

static int MyFilter( sqlite3_vtab_cursor *p_vtc, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ) // finished: 80%
{
    printf("MyFilter\n");
    //根据条件来筛选出符合条件的行
    return SQLITE_OK;
}

static int MyNext(sqlite3_vtab_cursor *cur) // finished: 100%
{
    printf("MyNext\n");
    curPos++;//Next时把cursor递增。严格说应该是cur结构体中带过来筛选条件,在这里根据筛选条件找Next,但例子就从简了
    return SQLITE_OK;
}

static int MyEof(sqlite3_vtab_cursor *cur) // finished: 100%
{
    printf("MyEof\n");
    //严格说应该是判断,符合cur结构体中带过来筛选条件的行是否结束,但例子就从简了
    if (curPos >= DATA_COUNT)
    {
        return 1;
    }
    else
    {//0 ~ DATA_COUNT-1
        return 0;
    }
}

static int MyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int column) // finished: 80%
{
    printf("MyColumn\n");
    switch (column)

    {
    case 0://id
        sqlite3_result_int(ctx, gIDinTable[curPos]);
        break;
    case 1://name
        sqlite3_result_text(ctx, gNameinTable[curPos], strlen(gNameinTable[curPos]), SQLITE_STATIC);
        break;
    default:
        break;
    }
    return SQLITE_OK;
}

static int MyRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid) // finished: 100%
{
    printf("MyRowid\n");
    *p_rowid = (sqlite_int64)curPos;
    return SQLITE_OK;
}

static int MyUpdate(sqlite3_vtab *pVTab,int argc,sqlite3_value **argv,sqlite_int64 *pRowid)
{
    printf("MyUpdate\n");
    return SQLITE_OK;
}

static int MyFindFunction( sqlite3_vtab *pVtab, int nArg,const char *zName,
                             void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
                             void **ppArg )
{
    printf("MyFindFunction\n");
    return SQLITE_OK;
}

static sqlite3_module myModule =
{
    1, /* iVersion */
    MyCreate, /* xCreate - create a vtable */
    MyConnect, /* xConnect - associate a vtable with a connection */
    MyBestIndex, /* xBestIndex - best index */
    MyDisconnect, /* xDisconnect - disassociate a vtable with a connection */
    MyDestroy, /* xDestroy - destroy a vtable */
    MyOpen, /* xOpen - open a cursor */
    MyClose, /* xClose - close a cursor */
    MyFilter, /* xFilter - configure scan constraints */
    MyNext, /* xNext - advance a cursor */
    MyEof, /* xEof - inidicate end of result set*/
    MyColumn, /* xColumn - read data */
    MyRowid, /* xRowid - read data */
    MyUpdate, /* xUpdate - write data */
    NULL, /* xBegin - begin transaction */
    NULL, /* xSync - sync transaction */
    NULL, /* xCommit - commit transaction */
    NULL, /* xRollback - rollback transaction */
    MyFindFunction, /*  xFindFunction - function overloading */
    NULL,
    NULL,
    NULL,
    NULL
};

int main()
{
    int ret;
    sqlite3* pDb = NULL;
    printf("Open db\n");
    ret = sqlite3_open("./my.db", &pDb);//Open the db file
    assert(SQLITE_OK == ret);

    //Create virtual table
    ret = sqlite3_create_module(pDb, "MyVT", &myModule, NULL);
    assert(SQLITE_OK == ret);
    printf("Create virtual table\n");
    ret = sqlite3_exec(pDb, "create virtual table virTable using MyVT", NULL, NULL, NULL);//Create a table
    assert(SQLITE_OK == ret);

    //Execute a select clause
    ret = sqlite3_exec(pDb, "select * from virTable", NULL, NULL, NULL);//Create a table
    assert(SQLITE_OK == ret);

    //Execute a select clause and get result
    sqlite3_stmt *stmt;
    ret = sqlite3_prepare_v2(pDb, "select * from virTable", -1, &stmt, NULL);
    printf("id  name\n");
    while (SQLITE_ROW == sqlite3_step(stmt))
    {
        int id = sqlite3_column_int(stmt, 0);
        const unsigned char* pName = sqlite3_column_text(stmt, 1);//pName会被sqlite3自动释放,不用外界释放
        printf("%-4d %s\n", id, pName);
    }
    sqlite3_finalize(stmt);
    assert(SQLITE_OK == ret);

    sqlite3_close(pDb);
    return 0;
}

  • rowid

SQL默认有一个rowid列,int64格式,这个列是自动生成的,一般是递增的,不用去指定。可以select语句把它显示出来。

  • 效率提升

BEGIN TRANSACTION - COMMIT :对于Insert和Update这样的有IO的操作,如果每个语句都单独执行,大量操作时就会有大量的IO操作,会非常慢。例如Insert 10000条数据会耗费十几秒的时间。

加速方法: 在批量语句前加 BEGIN TRANSACTION, 之后加 COMMIT, 这样所有的IO操作会被缓存,到COMMIT时统一执行只进行一次IO操作。效果非常明显,几百倍的速度提升。

还有一个"PRAGMA synchronous = OFF"语句,但测试过不起作用,速度没加快。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值