SQLite數據庫C語言接口使用實例教程

SQLiteC語言操作說明


SQLITE3

在這裏插入圖片描述
​ 在開始之前先介紹一下什麼是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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h> 

/**
 * @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 <stdio.h>
#include <stdlib.h>
#include <sqlite3.h> 
#include <string.h>

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 <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>

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 <stdio.h>
#include <stdlib.h>
#include <sqlite3.h> 

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 <stdio.h>
#include <stdlib.h>
#include <sqlite3.h> 
#include <string.h>


#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>


/****

 * */

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權威指南(中文和英文)
掃碼下載:
在這裏插入圖片描述

二維碼無效的情況下,可通過關注公衆號獲取:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章