文章目錄
SQLiteC語言操作說明
SQLITE3
在開始之前先介紹一下什麼是SQLite
數據庫,SQLite
是一款開源的、嵌入式關係型數據庫,SQLite
非常適合前途是產品,因爲其沒有獨立運行的進程,它與服務的應用程序在應用程序的進程空間內共生共存。它的代碼和應用程序的代碼是在一起的或者說是嵌入其中,作爲託管它的程序的一部分。
爲什麼學習數據庫建議你先學習SQLite
數據庫,特別是嵌入式開發的人員。因爲SQLite
的作者都說過SQLite
是一款無論你使用的是什麼操作系統,都能夠在5分鐘內完成,數據庫的安裝配置,以及創建自己的第一個數據庫。
爲什麼要用 SQLite
?
- 不需要一個單獨的服務器進程或操作的系統(無服務器的)。
SQLite
不需要配置,這意味着不需要安裝或管理。- 一個完整的
SQLite
數據庫是存儲在一個單一的跨平臺的磁盤文件。 SQLite
是非常小的,是輕量級的,完全配置時小於400KiB
,省略可選功能配置時小於250KiB
。SQLite
是自給自足的,這意味着不需要任何外部的依賴。SQLite
事務是完全兼容 ACID 的,允許從多個進程或線程安全訪問。SQLite
支持SQL92
(SQL2
)標準的大多數查詢語言的功能。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%';
限定和排序
- 可以使用
limit
和offset
關鍵字限定結果集的大小和範圍,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權威指南(中文和英文)
掃碼下載:
二維碼無效的情況下,可通過關注公衆號獲取: