SQLite数据库入门

2019-10-27

关键字:sqlite3、Linux数据库


嵌入式设备通常都不会有太丰富的计算与内存资源,为了能在这种资源紧张型的嵌入式设备中也能正常使用与PC端类似的数据库软件,就必须专门针对嵌入式设备开发轻量级数据库。目前嵌入式领域的数据库软件主要有以下几种:

1、SQLite

一种关系型数据库,体积小且支持 ACID 事务。

2、Firebird

一种关系型数据库,功能强大,支持存储过程、SQL兼容等特性。

3、Berkeley DB

这种数据库中并不像常规数据库一样有服务器的概念。它的程序库是直接链接到应用程序中的。

4、eXtremeDB

一种内存数据库,运行效率较高。

SQLite 是一种在嵌入式设备领域比较常见的一种轻量级数据库软件。它诞生于 2000 年,是一个基于C语言的开源软件。目前 SQLite 数据库的主流版本已经更新到第 3 大版,即我们常见的 sqlite3。

SQLite 数据库具有以下特性:

1、零配置,软件无需安装和管理配置;

2、整个数据库都存储在同一个磁盘中;

3、兼容性好,数据库文件可以在不同字节序的机器间自由共享;

4、支持的数据库大小上限是2TB;

5、轻量化,源码只有3万多行;

6、操作速度较快;

SQLite数据库的创建方式有两种:

1、手工创建

主要是指通过进入 sqlite3 的命令行通过 SQL 命令来创建。

2、代码创建

安装:

如果是 Linux PC系统,可以直接使用 sudo apt install sqlite3 命令来在线安装。软件很小,就几兆字节。

如果是嵌入式设备,通常直接将编译好的 sqlite3 程序下载进去就可以运行的了。

创建数据库:

sqlite3 mydb.db

上述命令可以直接在当前目录下创建一个名称为 mydb 的 SQLite 数据库文件,并进入到该数据库中。

常用命令:

SQLite中的命令主要可以分为两种:一种是以 . 开头的命令,这种命令称为“系统命令”,主要用于对 SQLite 软件发号施令。另一种是普通的 SQL 命令,这种命令是必须要以 ; 号结尾的,这种命令主要用于操作数据库或数据表。

创建数据表:

create table stu(id Integer, name char, score Float, address string);

创建一张名称为 stu 的数据表,表的结构如命令括号中所示。

删除数据表:

drop table tbname;

delete table tbname;

增删改查:

insert into stu values(1001, ‘lemontea1‘, 76.2, "guangdong.zhongshan");

insert into stu values(1002, "lemontea2", 86.2, ‘sicuan.leshan‘);

insert into stu(id, name) values(1003, ‘lemontea3‘);

以上是插入数据的几种主要的命令形式。SQLite命令中字符串的引号单双引号可以通用。指定字段插入的语法与普通 SQL 是如出一辙的。

delete from stu where id=1003;

delete from stu;

删除数据。表名后有条件限制则只删除满足条件的记录项。表名后若无条件限制,则将整张表删除掉。与普通 SQL 基本通用。

update stu set score=96.1 where name=‘lemontea1‘;

update stu set id=1033, score=96.1 where name=‘lemontea1‘;

修改数据记录。既可以修改单个字段的值也可以同时修改多个字段的值。其使用方式也与普通 SQL 基本一致。

select * from stu;

select name from stu;

select name, score from stu;

select * from stu where score < 80 and score > 70;

查询数据的 SQL 语句与普通 SQL 也没太大差别。

修改表:

alter table stu add column desc char;

为已存在的表添加一个字段。

alter table stu rename to stu1;

将数据表 stu 更名为 stu1。

SQLite中虽然可以通过 alter 来新增一个字段,但是却没有可以直接删除某一字段的命令。想要删除数据表中某一字段,可以通过间接的方式来进行:

1、create table stu_tmp as select id, name, score from stu;

2、drop table stu;

3、alter table stu_tmp rename to stu;

.databases:

列出当前所打开的数据库的名称与文件路径。

.tables

列出当前数据库下的所有数据表。

.schema tbname

查询指定数据表的建表语句,或者说查看指定数据表的表结构。

通过代码操作SQLite:

本节主要记载在 Linux 开发中通过C语言操作SQLite的方法。

SQLite 对外开放的函数接口非常多,本节仅记载几个基础的常用的函数,更多函数的接口及释义还需自行参阅SQLite官方文档,这里贴出官方文档的下载路径:https://www.sqlite.org/2019/sqlite-doc-3300100.zip 。另外,官方网站的文档下载的速度实在是太慢了,我这里已将下载好的文档上传至百度云,有需要的同学可以直接下载我百度云上的:https://pan.baidu.com/s/1TYsog_56eorCOXynSAFh4Q  

如果在编译的时候提示找不到 sqlite3.h 头文件的话,只需要安装一下 sqlite3 的SDK即可: sudo apt install libsqlite3-dev 

打开SQLite:

int sqlite3_open(char *path, sqlite3 **db);

参数 path 表示数据库文件的路径。

参数 db 表示指向 sqlite3 的句柄指针。

该函数执行成功时返回值0,失败时返回相应错误码。

关闭SQLite:

int sqlite3_close(sqlite3 *db);

执行成功时返回值0,失败时返回相应错误码。

提取错误信息:

const char* sqlite3_errmg(sqlite3 *db);

将操作SQLite时产生的错误码转换成字符串信息。

执行SQL语句:

int sqlite3_exec(sqlite3 *db, const char *sql, int (*callback)(void *para, int f_num, char **f_value, char **f_name), void *args, char **errmsg);

参数 callback 是一个查询执行结果的回调函数的指针。

int (*callback)(void *para, int f_num, char **f_value, char **f_name);

这个函数主要用于执行SQLite查询时的结果回调。每找到一条记录就会自动调用一次这个回调函数。

参数 para 表示传递给回调函数的参数。

参数 f_name 表示记录中包含的字段数目。

参数 f_value 表示包含每个字段值的指针数组。

参数 f_name 表示包含每个字段名称的指针数组。

这个函数执行成功时会返回值0,失败时返回-1。

参数 args 是给前一个参数 callback 的函数传参。

参数 errmsg 就是错误信息。

这个函数执行成功时会返回 SQLITE_OK。

不使用回调的方式来查询数据:

上面的 sqlite3_exec() 函数通过执行 SQL 的方式来查询数据,查询结果只能通过回调来拿到。SQLite 还提供了另外一种查询方式,这种查询方式不需要回调函数来接收查询结果。

int sqlite3_get_table(sqlite3 *db, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg);

参数 resultp 表示用来指向查询结果的指针。三级指针,通常我们需要定义一个二级指针,然后取地址传过去。

参数 nrow 表示满足条件的记录数目。

参数 ncolumn 表示每条记录所包含的字段数目。

参数 errmsg 用于存储错误信息。

执行成功时返回值0,失败时返回相应错误码。

以下是一个简单的SQLite实现的管理学生成绩的小示例,这个示例包含了创建数据库、数据表以及对数据表的增删改查。同时还应用了两种查询方式,其源码如下所示:

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

#define DB "stu.db"

//compile:  gcc student.c -lsqlite3

int do_insert(sqlite3 *db)
{
    int id;
    char name[32] = {};
    float score;
    char sql[128] = {};
    char *errmsg;
    
    printf("id:");
    scanf("%d", &id);
    getchar(); //消化掉 \n 字符.
    
    printf("name:");
    scanf("%s", &name);
    getchar(); //消化掉 \n 字符.
    
    printf("score:");
    scanf("%f", &score);
    getchar(); //消化掉 \n 字符.
    
    sprintf(sql, "insert into stu values(%d, ‘%s‘, %f)", id, name, score);
    
    if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        printf("insert error:%s\n", errmsg);
    }
    else
    {
        printf("insert done\n");
    }
    
    return 0;
}

int do_delete(sqlite3 *db)
{
    int id;
    char sql[128] = {};
    char *errmsg;
    
    printf("id:");
    scanf("%d", &id);
    getchar(); //消化掉 \n 字符.
    
    sprintf(sql, "delete from stu where id=%d", id);
    
    if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        printf("delete error:%s\n", errmsg);
    }
    else
    {
        printf("delete done\n");
    }
    
    return 0;
}

int do_update(sqlite3 *db)
{
    int id;
    float score;
    char sql[128] = {};
    char *errmsg;
    
    printf("id:");
    scanf("%d", &id);
    getchar(); //消化掉 \n 字符.
    
    printf("score:");
    scanf("%f", &score);
    getchar(); //消化掉 \n 字符.
    
    sprintf(sql, "update stu set score=%f where id=%d", score, id);
    
    if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        printf("update error:%s\n", errmsg);
    }
    else
    {
        printf("update done\n");
    }
    
    return 0;
}

int callback(void *para, int f_num, char **f_value, char **f_name)
{
    int i = 0;
    
    for(i = 0; i < f_num; i++)
    {
        printf("%-11s ", f_value[i]);
    }
    putchar(‘\n‘);
    
    return 0;
}

int do_query(sqlite3 *db)
{
    char sql[128] = {};
    char *errmsg;
    
    sprintf(sql, "select * from stu");
    
    if(sqlite3_exec(db, sql, callback, NULL, &errmsg) != SQLITE_OK)
    {
        printf("query error:%s\n", errmsg);
    }
    else
    {
        printf("query done\n");
    }
    
    return 0;
}

int do_query_no_callback(sqlite3 *db)
{
    char sql[128] = {};
    char *errmsg;
    char **resultp;
    int nrow;
    int ncoloumn;
    int index;
    
    int i, j;
    
    sprintf(sql, "select * from stu");
    
    if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncoloumn, &errmsg) != SQLITE_OK)
    {
        printf("query error:%s\n", errmsg);
    }
    else
    {
        printf("query done\n");
    }
    
    for(j = 0; j < ncoloumn; j++)
    {
        printf("%-11s ", resultp[j]);
    }
    putchar(‘\n‘);
    
    index = ncoloumn;
    for(i = 0; i < nrow; i++)
    {
        for(j = 0; j < ncoloumn; j++)
        {
            printf("%-11s ", resultp[index++]);
        }
        putchar(‘\n‘);
    }
    
    return 0;
}

int main(int argc, const char *argv[])
{
    sqlite3 *db;
    char *errmsg;
    int cmd;
    
    if(sqlite3_open(DB, &db) != 0)
    {
        printf("open error\n");
        return -1;
    }
    
    if(sqlite3_exec(db, "create table stu(id Integer, name char, score Float)", NULL, NULL, &errmsg) != SQLITE_OK)
    {
        printf("create table error:%s\n", errmsg);
    }
    
    while(1)
    {
        printf("\n**************************************\n");
        printf("1:insert\n2:delete\n3:query\n4:update\n5:quit\n6:query2\n");
        printf("**************************************\n\n");
        
        scanf("%d", &cmd);
        switch(cmd)
        {
            case 1:
                do_insert(db);
            break;
            case 2:
                do_delete(db);
            break;
            case 3:
                do_query(db);
            break;
            case 4:
                do_update(db);
            break;
            case 5:
                return 0;
        case 6:
        do_query_no_callback(db);
        break;
            default:break;
        }
    }

    return 0;
}

相关推荐