SQLite数据库C语言接口使用实例教程

文章目录

  • SQLiteC语言操作说明
    • `SQLITE3`
    • 为什么要用 `SQLite`?
    • `SQLite`命令
    • 常用SQL语句
    • 创建表
    • 修改表
    • 数据表测查询
      • 限定和排序
      • 多表连接
      • 外连接
      • 交叉连接
      • 子查询
      • 条件结果
      • 处理SQLite中的NULL
    • 高级SQL
      • 修改数据
        • 插入数据
        • 跟新记录
        • 删除数据
    • 本文用到的函数说明
    • 数据的删除
      • delete的实现
    • 插入数据
      • 更新数据
    • 使用二进制的形式对数据库进行保存

SQLiteC语言操作说明


SQLITE3

SQLite数据库C语言接口使用实例教程_第1张图片
​ 在开始之前先介绍一下什么是SQLite数据库,SQLite是一款开源的、嵌入式关系型数据库,SQLite非常适合前途是产品,因为其没有独立运行的进程,它与服务的应用程序在应用程序的进程空间内共生共存。它的代码和应用程序的代码是在一起的或者说是嵌入其中,作为托管它的程序的一部分。

​ 为什么学习数据库建议你先学习SQLite数据库,特别是嵌入式开发的人员。因为SQLite的作者都说过SQLite是一款无论你使用的是什么操作系统,都能够在5分钟内完成,数据库的安装配置,以及创建自己的第一个数据库。


为什么要用 SQLite

  • 不需要一个单独的服务器进程或操作的系统(无服务器的)。
  • SQLite 不需要配置,这意味着不需要安装或管理。
  • 一个完整的 SQLite 数据库是存储在一个单一的跨平台的磁盘文件。
  • SQLite 是非常小的,是轻量级的,完全配置时小于 400KiB,省略可选功能配置时小于250KiB
  • SQLite 是自给自足的,这意味着不需要任何外部的依赖。
  • SQLite 事务是完全兼容 ACID 的,允许从多个进程或线程安全访问。
  • SQLite 支持 SQL92SQL2)标准的大多数查询语言的功能。
  • SQLite 使用 ANSI-C 编写的,并提供了简单和易于使用的 API
  • SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中运行

​ 好了说了那么多,现在直接进入正题,进入 [地址]:https://www.sqlite.org/index.html 下载最新的SQLite源码,按照源码中文档安装数据库,一下的代码都是在UBUNTU 16.04上测试通过的代码 ,测试代码的git仓库见文末。


SQLite命令

​ 将命令按照操作的性质可以分为一下几种;

DDL- 数据定义语言

CREATE 创建一个新的表,一个表的视图,或者数据库中其他的对象
ALTER 修改数据库中某个已有的数据库对象,比如一个表
DROP 删除整个表,或者表的视图,或者数据库中其他对象

DML- 数据操作语言

INSERT 创建一条记录
UPDATE 修改记录
DELETE 删除记

DQL- 数据查询语言

命令 描述
SELECT 从一个或者多个表中检索记录
  • SQLite的一些简单的使用,以及命令可以参考 [地址]:https://www.runoob.com/sqlite/sqlite-tutorial.html
  • 这里就主要说一些使用的场景

常用SQL语句

$sqlite3 test.db #使用sqlite3打开一个数据库,如果数据库不存在就创建对应的数据库
.echo on  # 在屏幕上打印执行的SQL语句
.mode column #以列的模式显示 结果
.headers on # 包含列名称
.nullvalue NULL # 将nulls打印成NULL

创建表

create [temp] table table_name (column_definitions [, constraints]);
#指定 temp说明创建的表是临时表,临时表只存活于当前会话,会话结束表会立即释放

修改表

lter table table{rename to name | add column column_def};
# alter table contacts add column email text not  null default '' collate nocase;

数据表测查询

select name from (select name, type_id from (select * from foods));
select heading from tables where predicate;
select * from dogs where color='purple' and grin= 'toothy';
# %可以与任一多个或者单个字符匹配,下划线可以与任一一个字符匹配
select id, name from foods where name like '%ac%p%';
select id, name from foods where name like '%ac%P%' and name not like '%Sch%';

限定和排序

  • 可以使用limitoffset关键字限定结果集的大小和范围,limit指定返回记录中的最大数量,offset指定偏移的记录数。
select * from food_types order by id limit 1 offset 1;
# 关键字offset在结果集中,跳过一行(Bakery),关键字limit限制最多返回一行(Cereal)

# order by使返回的结果按照某种排序进行输出-asc(默认的升序)或desc(降序)。
select * from foods where name like 'B%' order by type_id desc, name limit 10;
# limit和offset一起使用时,可以使用逗号代替offset
# 有些人可能认为这里的语法应该倒过来,在SQLite中,使用缩写时,offset总是优先limit,紧随limit关键字的值是offset 2 ,也要注意到,offset依赖于limit, 也就是说,可以只使用Limit不到offset但是反过来不行。
select * from foods where name like 'B%' order by type_id desc, name limit 1 offset 2;
select * from foods where name like 'B%' order by type_id desc, name limit 2, 1;

多表连接

​ 连接(join)是多表(关系)数据工作的关键,它是select命令的第一个操作,连接操作的结果作为输入,供select语句的其他部分(过滤)处理。

select foods.name, food_types_.name from foods, food_types where fods.type_id =food_types.id limit 10;

外连接

# 外链接相当于取两表相交的地方
select * from foods inner join food_types  on foods.id = food_types.id;

交叉连接

select * from foods, food_types;

子查询

# 子查询就是子啊select语句又嵌套select语句。
select 1 in (1,2,3);
select count(*) from foods where type_id in (1,2);
select count(*) from foods where type_id in (select id from food_types where name='Bakery' or name='Cereal');

条件结果

select name || case type_id 
				when 7 then ' is a drink '
				when 8 then 'is a fruit'
				when 9 then ' is junkfood'
				when 13 then ' is seafood'
				else null
				end description
from foods 
where description is not null 
order by name
limit 10;

处理SQLite中的NULL

  • 可以通过is null 或者is not null操作符监测null是否 存在。
  • null不等于任何值,包含NULL。

高级SQL

修改数据

插入数据

insert into table (column_list) values (value_list);
# insert into foods (nam, type_id) values ('Cinnamon Bobla', 1);

跟新记录

update table set update_list where predicate;

删除数据

delete from table where predicate;
delete from foods where name = 'CHOCOLATE BOBKA';


本文用到的函数说明

/*
** Open a new database handle.
*/
//< 打开操作句柄
int sqlite3_open(
  const char *zFilename,  //< 文件名字
  sqlite3 **ppDb   //< 操作句柄
)

//< 返回UTF8编码的英文常见错误
/*
** Return UTF-8 encoded English language explanation of the most recent
** error.
*/
const char *sqlite3_errmsg(sqlite3 *db)
    
/*
** Execute SQL code.  Return one of the SQLITE_ success/failure
** codes.  Also write an error message into memory obtained from
** malloc() and make *pzErrMsg point to that message.
**
** If the SQL is a query, then for each row in the query result
** the xCallback() function is called.  pArg becomes the first
** argument to xCallback().  If xCallback=NULL then no callback
** is invoked, even for queries.
*/
 //< 执行SQL语句
int sqlite3_exec(
  sqlite3 *db,                /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  sqlite3_callback xCallback, /* Invoke this callback routine,回调函数,执行的SQL语句有输出时 */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
)
    
/*
** Windows systems should call this routine to free memory that
** is returned in the in the errmsg parameter of sqlite3_open() when
** SQLite is a DLL.  For some reason, it does not work to call free()
** directly.
**
** Note that we need to call free() not sqliteFree() here.
*/
    
void sqlite3_free(char *p){ free(p); }

/*
** The type for a callback function.
*/
//< 回调函数定义
typedef int (*sqlite3_callback)(void*,int,char**, char**);
/*
** A function to close the database.
**
** Call this function with a pointer to a structure that was previously
** returned from sqlite3_open() and the corresponding database will by closed.
**
** All SQL statements prepared using sqlite3_prepare() or
** sqlite3_prepare16() must be deallocated using sqlite3_finalize() before
** this routine is called. Otherwise, SQLITE_BUSY is returned and the
** database connection remains open.
*/
//< 关闭SQL句柄
int sqlite3_close(sqlite3 *);

​ 实现创建数据表,向数据表中添加数据,并查询对应表格数据,使用回调函数打印出查询出的数据。

creat_db_datebase.c

#include 
#include 
#include 
#include  

/**
 * @brief  callback
 * @note    回调函数,用于获取查看SQL语句返回数据
 * @param  *NotUsed:sqlite3_exec函数的第四个参数传入的数据 
 * @param  argc: 数据的行数
 * @param  **argv: 列数据数组
 * @param  **azColName: 列标识符数组
 * @retval 
 */
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
   int i;
   for(i=0; i<argc; i++){
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;
}

int main(int argc, char* argv[])
{
   sqlite3 *db;
   char *zErrMsg = 0;
   int  rc;
   char *sql;
   char sql_str[1024];
   /* Open database */
   //< 打开数据库文件,如果对应的数据库不存在就创建
   rc = sqlite3_open("test.db", &db);
   if( rc ){
      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
      exit(0);
   }else{
      fprintf(stdout, "Opened database successfully\n");
   }

   /* Create SQL statement */
   //< 建表语句定义
   /* 创建主键 */ //"ID INT PRIMARY KEY     NOT NULL," 
   //< 表格不存在就创建表格,存在不重新创建,但是返回成功
   sql = "CREATE TABLE IF NOT EXISTS class("  \
         "ID INT PRIMARY KEY     NOT NULL," \
         "NAME           TEXT    NOT NULL," \
         "AGE            INT     NOT NULL," \
         "ADDRESS        CHAR(50)," \
         "SALARY         REAL );";

   /* Execute SQL statement */
   //< 返回程序生成的执行的任何返回
   rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
   if( rc != SQLITE_OK ){
   fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      fprintf(stdout, "Table created successfully\n");
   }

    memset(sql_str, 0, sizeof(sql_str));

    //< replace 官网上很少说名,其他写SQLite数据库的文章也很少介绍,我这里理解的 replace就是
    //< update与insert的合体,当存在记录的时候就相当于使用update  当记录不存在的时候就相当与使用insert
    snprintf(sql_str, sizeof(sql_str), "replace into class"
                "(ID, NAME, AGE, ADDRESS, SALARY)"
                " values (%d, '%s', %d, '%s', %f)",
                1, "alice", 18, "10.1.1.1", 100000.123
                     );
    rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Table replace successfully\n");
    }

    memset(sql_str, 0, sizeof(sql_str));

    //< 查询class表中的数据
    memcpy(sql_str, "select * from class;", sizeof(sql_str));
    rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Table created successfully\n");
    }


   sqlite3_close(db);
   return 0;
}

数据的删除

delete的实现

衔接[SQLite数据库-数据表的创建,插入数据和查询数据]:https://blog.csdn.net/andrewgithub/article/details/100717099

​ 上一篇文章讲述了,数据库的创建、数据的插入和删除,这里衔接上一篇文章主要讲述数据的删除。

​ 删除数据,注意并不是删除一个数据表,只是删除一个数据表中的一个数据项;

creat_db_delete.c 代码仓库路径:https://github.com/zzu-andrew/linux-sys/tree/dfew/SQLite

#include 
#include 
#include  
#include 

static int callback(void *data, int argc, char **argv, char **azColName){
   int i;
   fprintf(stderr, "%s: ", (const char*)data);
   for(i=0; i<argc; i++){
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;
}

int main(int argc, char* argv[])
{
   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;
   char sql_str[512];
   const char* data = "Callback function called";

   /* Open database */
   rc = sqlite3_open("test.db", &db);
   if( rc ){
      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
      exit(0);
   }else{
      fprintf(stderr, "Opened database successfully\n");
   }


   /* Create SQL statement */
   //< 建表语句定义
   /* 创建主键 */ //"ID INT PRIMARY KEY     NOT NULL," 
   //< 表格不存在就创建表格,存在不重新创建,但是返回成功
   sql = "CREATE TABLE IF NOT EXISTS class("  \
         "ID INT PRIMARY KEY     NOT NULL," \
         "NAME           TEXT    NOT NULL," \
         "AGE            INT     NOT NULL," \
         "ADDRESS        CHAR(50)," \
         "SALARY         REAL );";

   /* Execute SQL statement */
   //< 返回程序生成的执行的任何返回
   rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
   if( rc != SQLITE_OK ){
   fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      fprintf(stdout, "Table created successfully\n");
   }

    memset(sql_str, 0, sizeof(sql_str));

    //< 插入一条,ID为2的数据
    snprintf(sql_str, sizeof(sql_str), "replace into class"
                "(ID, NAME, AGE, ADDRESS, SALARY)"
                " values (%d, '%s', %d, '%s', %f)",
                2, "alice", 18, "10.1.1.1", 100000.123
                     );
    rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Table replace successfully\n");
    }

    memset(sql_str, 0, sizeof(sql_str));

    //< 查询class表中的数据
    fprintf(stdout, "----------------------------------------------------------!\n");
    fprintf(stdout, "Before delete !!\n");
    memcpy(sql_str, "select * from class;", sizeof(sql_str));
    rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Table created successfully\n");
    }

   /* Create merged SQL statement */
   //< 将 ID = 2的数据删除
    fprintf(stdout, "----------------------------------------------------------!\n");
    fprintf(stdout, "after delete !!\n");
   sql = "DELETE from class where ID=2; " \
         "SELECT * from class";

   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
   if( rc != SQLITE_OK ){
      fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      fprintf(stdout, "Operation done successfully\n");
   }
 
   sqlite3_close(db);
   return 0;
}
  • 数据表中 ID=2的数据项以被删除
Opened database successfully
Table created successfully
Table replace successfully
----------------------------------------------------------!
Before delete !!
(null): ID = 1
NAME = alice
AGE = 18
ADDRESS = 10.1.1.1
SALARY = 100000.123

(null): ID = 2
NAME = alice
AGE = 18
ADDRESS = 10.1.1.1
SALARY = 100000.123

Table created successfully
----------------------------------------------------------!
# 数据表中 ID=2的数据项以被删除
after delete !!
Callback function called: ID = 1
NAME = alice
AGE = 18
ADDRESS = 10.1.1.1
SALARY = 100000.123

Operation done successfully

插入数据

#include 
#include 
#include 

static int callback(void *NotUsed, int argc, char **argv, char **azColName){
   int i;
   for(i=0; i<argc; i++){
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;
}

int main(int argc, char* argv[])
{
   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;

   /********************第一步,打开数据库文件,获取数据库文件操作句柄*************************/
   rc = sqlite3_open("test.db", &db);
   if( rc ){
      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
      exit(0);
   }else{
      fprintf(stderr, "Opened database successfully\n");
   }

   /********************第二步、定义数据操作语句***********************/
   sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) "  \
         "VALUES (1, 'Paul', 32, 'California', 20000.00 ); " \
         "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) "  \
         "VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); "     \
         "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \
         "VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );" \
         "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \
         "VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );";

    /********************第三步、执行建表语句建立数据表**********************/
   rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
   if( rc != SQLITE_OK ){
      fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      fprintf(stdout, "Records created successfully\n");
   }
   sqlite3_close(db);
   return 0;
}

更新数据

#include 
#include 
#include  

static int callback(void *data, int argc, char **argv, char **azColName){
   int i;
   fprintf(stderr, "%s: ", (const char*)data);
   for(i=0; i<argc; i++){
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;
}
//FIXME:
// TODO:
int main(int argc, char* argv[])
{
   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;
   const char* data = "Callback function called";

   /* Open database */
   rc = sqlite3_open("test.db", &db);
   if( rc ){
      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
      exit(0);
   }else{
      fprintf(stderr, "Opened database successfully\n");
   }

   /* Create merged SQL statement */
   sql = "UPDATE COMPANY set SALARY = 25000.00 where ID=1; " \
         "SELECT * from COMPANY";

   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
   if( rc != SQLITE_OK ){
      fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      fprintf(stdout, "Operation done successfully\n");
   }
   sqlite3_close(db);
   return 0;
}
//TODO: 部分的sqlite版本中,对于主键为null使的处理方式不同

 *  1.null不等于任何值,包括它自身,当主键为null时,会导致插入的数据会持续增长,因为数据数据库插入数据的时候
 *  找不到相同的主键组合(NULL != NULL)
 *  2.将主键为null是认为是相同的如有三个主键的组合(1, 2, null) == (1, 2, null)
 *  
 *  处理方式不同,这里处理函数执行之后看到的结果是不一样的。


/*
+--------+     +-------+     +--------------+     +---------------+
| B-tree | --> | Pager | --> |      os      | --> | Database File |
+--------+     +-------+     +--------------+     +---------------+
                               |
                               |
                               v
                             +--------------+
                             | Journal File |
                             +--------------+
*/
#include 
#include 
#include  
#include 


#define create_test_table "CREATE TABLE test_not_null("  \
                            "id                 integer," \
                            "idx1                integer," \
                            "chan                 integer," \
                            "name           TEXT    NOT NULL," \
                            "age            INT     NOT NULL," \
                            "address        CHAR(50)," \
                            "salary         REAL,"\
                            "primary key(id, idx1, chan));"

#define create_test_null_table "CREATE TABLE test_null("  \
                            "id                 integer," \
                            "idx1                integer," \
                            "chan                 integer," \
                            "name           TEXT    NOT NULL," \
                            "age            INT     NOT NULL," \
                            "address        CHAR(50)," \
                            "salary         REAL,"\
                            "primary key(id, idx1, chan));"

static int callback(void *NotUsed, int argc, char **argv, char **azColName){
   int i;
   for(i=0; i<argc; i++){
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;
}

//TODO: 部分的sqlite版本中,对于主键为null使的处理方式不同
/***
 *  1.null不等于任何值,包括它自身,当主键为null时,会导致插入的数据会持续增长,因为数据数据库插入数据的时候
 *  找不到相同的主键组合(NULL != NULL)
 *  2.将主键为null是认为是相同的如有三个主键的组合(1, 2, null) == (1, 2, null)
 *  
 *  处理方式不同,这里处理函数执行之后看到的结果是不一样的。
 * */

int main(int argc, char* argv[])
{
   sqlite3 *db;
   char *zErrMsg = 0;
   int  rc;                                                   
   char sql_str[512]; 
   int i = 0;   
   int j = 0;                                                                 

   /* Open database */
   //< 如果文件存在就打开数据库文件
   //< 如果文件不存在就打开一个数据库,等有实际操作了在创建该数据库文件
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
   rc = sqlite3_open("test.db", &db);
   if( rc ){
      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
      exit(0);
   }else{
      fprintf(stdout, "Opened database successfully\n");
   }

   /***
    * 创建含有创建主键全不为null的表
    * 
    * */
   rc = sqlite3_exec(db, create_test_table, callback, 0, &zErrMsg);
   if( rc != SQLITE_OK ){
   fprintf(stderr, "SQL test: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      fprintf(stdout, "Table created successfully\n");
   }

    /***
    * 创建用于测试主键中含有null时的表
    * 
    * */
   rc = sqlite3_exec(db, create_test_null_table, callback, 0, &zErrMsg);
   if( rc != SQLITE_OK ){
   fprintf(stderr, "SQL test: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      fprintf(stdout, "Table created successfully\n");
   }
    
    for (j = 0; j < 2; j ++)
    {
        /**
         * @brief 循环写入主键中没有null的数据 
         * 
         */
        for (i = 0; i < 30; i++)
        {
            memset(sql_str, 0, sizeof(sql_str));
            snprintf(sql_str, sizeof(sql_str), 
                "replace into test_not_null(id, idx1, chan, name, age)"
                "values(%d, %d, %d, '%s', %d);",
                    i, 2, 3, "Mack", i);
            rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
            if( rc != SQLITE_OK ){
            fprintf(stderr, "SQL error: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
            }else{
                fprintf(stdout, "Table created successfully\n");
            }
        }
        
        /**
         * @brief 循环写入主键中含有null的数据表
         * 
         */
        for (i = 0; i < 30; i++)
        {   
            memset(sql_str, 0, sizeof(sql_str));
            snprintf(sql_str, sizeof(sql_str), 
                "replace into test_null(id, idx1, name, age)"
                "values(%d, %d, '%s', %d);",
                    i, 2, "Mack", i);
            rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
            if( rc != SQLITE_OK ){
            fprintf(stderr, "SQL error: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
            }else{
                fprintf(stdout, "Table created successfully\n");
            }
        }
    }

    //< 查询,test_not_null表中的数据
    memcpy(sql_str, "select * from test_not_null;", sizeof(sql_str));
    rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Table created successfully\n");
    }

    //< 查询,test_null表中的数据
    memcpy(sql_str, "select * from test_null;", sizeof(sql_str));
    rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Table created successfully\n");
    }

   sqlite3_close(db);
   return 0;
}

使用二进制的形式对数据库进行保存

  • 说明:有很多很复杂的数据库保存的时候很难保存,可以直接使用二进制的形式将数据库
  • 按照一个整体进行保存,这样能够很大程度上将低数据表设计的难度
#include 
#include 
#include 
#include 


/****

 * */

typedef struct school
{
    int teacher_num;
    int student_num;
    int bicycle_num;
}SCHOOL;


/**
 * @brief  callback
 * @note    回调函数,用于获取查看SQL语句返回数据
 * @param  *NotUsed:sqlite3_exec函数的第四个参数传入的数据 
 * @param  argc: 数据的行数
 * @param  **argv: 列数据数组
 * @param  **azColName: 列标识符数组
 * @retval 
 */
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
   int i;
   SCHOOL school_temp;
   for(i=0; i<argc; i++){
       if (0 == strcmp("school", azColName[i]))
       {
            memcpy(&school_temp, argv[i], sizeof(school_temp));
            printf("teacher number  = [%d], student number = [%d], bicycle number = [%d]\n\n", 
                school_temp.teacher_num, school_temp.student_num, school_temp.bicycle_num);
       }
       else
       {
           printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
       }
       
        
   }
   printf("\n");
   return 0;
}


int main(int argc, char **argv)
{
    sqlite3 *db;
    char *zErrMsg = 0;
    int  rc;
    char *sql;
    char sql_str[1024];
    SCHOOL ZZU;
    sqlite3_stmt *stmt;
    const char* tail;

    memset(&ZZU, 0, sizeof(ZZU));
    ZZU.teacher_num = 35000;
    ZZU.student_num = 90000;
    ZZU.bicycle_num = 20000;
    
    /* Open database */
    //< 打开数据库文件,如果对应的数据库不存在就创建
    rc = sqlite3_open("test.db", &db);
    if( rc ){
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        fprintf(stdout, "Opened database successfully\n");
    }

    /* Create SQL statement */
    //< 建表语句定义
    /* 创建主键 */ //"ID INT PRIMARY KEY     NOT NULL," 
    //< 表格不存在就创建表格,存在不重新创建,但是返回成功
    sql = "CREATE TABLE IF NOT EXISTS test_blob("  \
            "id             INT," \
            "NAME           TEXT," \
            "school         blob," \
            "ADDRESS        CHAR(50)," \
            "primary key(ID));";

    /* Execute SQL statement */
    //< 返回程序生成的执行的任何返回
    rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Table created successfully\n");
    }


    memset(sql_str, 0, sizeof(sql_str));
    snprintf(sql_str, sizeof(sql_str), "replace into test_blob"
                "(id, NAME, school, ADDRESS)"
                " values (%d, '%s', ?, '%s')",
                1, "ZZU", "10.1.1.1");

    rc = sqlite3_prepare(db, sql_str, (int)strlen(sql), &stmt, &tail);
    if(rc != SQLITE_OK) {
        fprintf(stderr, "Error: %s\n", tail);
    }

    /***
     * int sqlite3_bind_blob(
        sqlite3_stmt *pStmt, //stmt描述语句
        int i, //< 第几个绑定参数(位置参数),也就是第几个问号,其中问号后面可以指定位置参数
        const void *zData, //< 绑定的参数数据
        int nData,   //< 二进制数据的大小
        void (*xDel)(void*) //< 数据的类型,说明需不需slqite对传入的数据进行管理
        )
     */
    sqlite3_bind_blob(stmt, 1, (void *)&ZZU, sizeof(ZZU), SQLITE_STATIC);
    //< 执行语句
    sqlite3_step(stmt);

    sqlite3_finalize(stmt);

    //< 查询class表中的数据
    memcpy(sql_str, "select * from test_blob;", sizeof(sql_str));
    rc = sqlite3_exec(db, sql_str, callback, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "get test_blob sucess!!\n");
    }

    sqlite3_close(db);

    return 0;    
}

代码仓库地址:https://github.com/zzu-andrew/linux-sys/tree/dfew/SQLite

本文参考书籍: SQLite3权威指南(中文和英文)
扫码下载:
SQLite数据库C语言接口使用实例教程_第2张图片

二维码无效的情况下,可通过关注公众号获取:
SQLite数据库C语言接口使用实例教程_第3张图片

你可能感兴趣的:(嵌入式-Linux)