如何快速使用C语言操作sqlite3

itopen组织
1、提供OpenHarmony优雅实用的小工具
2、手把手适配riscv + qemu + linux的三方库移植
3、未来计划riscv + qemu + ohos的三方库移植 + 小程序开发
4、一切拥抱开源,拥抱国产化

一、sqlite3库介绍

sqlite3库可从官网下载,当前版本为sqlite3 3.45.3
https://www.sqlite.org/download.html

二、sqlite3编译

2.1 x86_64架构安装

2.1.1 命令安装

sudo apt-get install sqlite3
sudo apt-get install libsqlite3-dev

2.1.2 源码编译安装

./configure
make -j$(nproc)
sudo make install

2.2 基于arm架构编译

2.2.1 下载工具链并安装

# 下载工具链
wget https://repo.huaweicloud.com/openharmony/compiler/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi/1.0/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi.tar.gz
tar -xvf prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi.tar.gz

# 设置工具链的路径
vim ~/.bashrc
# 最后一行添加
export PATH=~/bin/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi/bin:$PATH
# 重置.bashrc
source ~/.bashrc

2.2.2 编译sqlite3

export CC=aarch64-linux-gnu-gcc
./configure --prefix=$PWD/_install CC=aarch64-linux-gnu-gcc --host=aarch64-linux
./configure --prefix=$PWD/_install
make -j$(nproc)
make install

2.3 基于riscv64架构编译

2.3.1 工具链安装

sudo apt-get install gcc-riscv64-linux-gnu

2.3.2 编译sqlite3

./configure --prefix=$PWD/_install CC=riscv64-linux-gnu-gcc --host=riscv64-linux
make -j$(nproc)
make install

三、接口介绍

参考链接:
https://geek-docs.com/sqlite

3.1 打开/创建数据库

int sqlite3_open(const char *filename, sqlite3 **ppDb);

3.2 关闭数据库

int sqlite3_close(sqlite3 *db);

3.3 执行sql语句

int sqlite3_exec(sqlite3*,
                 const char *sql,
                 int (*callback)(void *, int, char **, char **),
                 void *arg,
                 char **errmsg);

3.4 获取结果内容

int sqlite3_get_table(sqlite3 *db,
                      const char *zSql,
                      char ***pazResult,
                      int *pnRow,
                      int *pnColumn,
                      char **pzErrmsg);

3.5 获取错误信息

const char *sqlite3_errmsg(sqlite3 *db);

3.6 释放表空间

void sqlite3_free_table(char **result);

四、sqlite3语句

4.1 sqlite数据类型

NULL:标识一个NULL值
INTEGER(intger):整数类型 int
REAL(real):浮点数 float,double
TEXT(text):字符串 ""
CHAR(char):字符''

4.2 创建表

create if not exists table table_name(column1 type1, column2 type2, column3 type3……);
# 例如创建一个名为dictory的表(sheet),里面有word、translation等字段
create table if not exists table_name(word text, translation text);

# not null 指定列不允许为NULLcreate table if not exists student(student_name txt not NULL, id txt not NULL, sex char);

# defaultinsert into语句没有提供特定的值时,为列提供一个默认值
create table if not exists student(student_name txt not NULL, id txt not NULL, sex char, grade integer default 99);

# unique 约束防止一个特定的列存在两个相同的值
create table if not exists student(student_name txt not NULL unique, id txt not NULL, sex char);

# check 约束 启用输入一条记录要检查值的条件。如果条件值为false,则记录违反了约束,且不能输入到表
create table if not exists student(student_name txt not NULL, id txt not NULL, sex char, grade intger check(grade > 0));

4.3 添加记录

insert into table_name(column1, column2, column3) values(val1, val2, val3);
insert into student(student_name, id, sex) values ('z3', '123', 'm');
或者
insert into student values('z3', '123', 'm');

4.4 查询

4.4.1 查看表结构

.schema

4.4.2 查看所有表

.tables

4.4.3 查看记录

# 获取所有数据记录
select * from table_name;

# 限制输出数据记录数量
select * from table_name limit val;

# 升序输出数据记录
select * from table_name order by column asc;
select * from dictory order by word asc;

# 降序输出数据记录
select * from table_name order by column desc;
select * from dictory order by word desc;

# 条件查询
select * from table_name where expression;
select * from table_name where column in ('val1', 'val2', 'val3');
select * from table_name where column = 'val1' or column = 'val2';
select * from table_name where column between val1 and val2;
select * from people where age>=10 and age <=15;
select name, age from people where age>= 10 and age<=15;
select * from table_name where column like 'xx%' or 'xxx_';
百分号(%)代表零个、一个或者多个数字或字符 
下划线(_)代表一个单一数字或字符 

4.5 修改数据记录

update table_name set column1=val1, column2=val2 where expression;
update student_info set id=0002, name=hencai where id=0001;

4.6 表中添加字段

alter table <table_name> add column <field> <type>;
alter table stu add column age integer;

4.7 删除数据记录

delete from table_name [where expression];
delete from stu where id=123;

4.8 删除表

drop table table_name;
drop table student;

4.9 删除指定字段

# step1:备份为temp id , name , age , sex
alter table info rename to temp;

# step2:创建新表
create table info(id, name, age);

#step3:导出到新表
insert into info select id, name, age from temp;

4.10 退出sqlite3

.quit

五、sqlite3库封装

5.1 封装库代码

代码来源 itopen组织: test

sqlite3_lib.c代码

#include "sqlite3_lib.h"

struct Sqlite3SyncOps sqlite3Sync[] = {
    {SQLITE3_SYNC_MODE_FULL, "PRAGMA synchronous = FULL"},
    {SQLITE3_SYNC_MODE_NORMAL, "PRAGMA synchronous = NORMAL"},
    {SQLITE3_SYNC_MODE_OFF, "PRAGMA synchronous = OFF"},
};

int CreateDatabase(char *dbname, sqlite3 **db)
{
    int ret = sqlite3_open(dbname, db);
    if (ret != SQLITE_OK) {
        printf("sqlite3_open error: %s\n", sqlite3_errmsg(*db));
        return -1;
    }
    return SQLITE_OK;
}

int SetDatabaseSync(sqlite3 *db, enum Sqlite3SyncMode mode)
{
    char *errmsg = NULL;
    if (db == NULL) {
        printf("db is NULL\n");
        return -1;
    }

    if (sqlite3_exec(db, sqlite3Sync[mode].sql, NULL, NULL, &errmsg)) {
        printf("sqlite3_exec error: %s\n", errmsg);
        sqlite3_free(errmsg);
        return -1;
    }

    return SQLITE_OK;
}

int CreateDataSheet(sqlite3 *db, const char *sql)
{
    char *errmsg = NULL;
    if (db == NULL) {
        printf("db is NULL\n");
        return -1;
    }

    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg)) {
        printf("sqlite3_exec error: %s\n", errmsg);
        sqlite3_free(errmsg);
        return -1;
    }
    return SQLITE_OK;
}

int InsertDataValue(sqlite3 *db, const char *sheet, const char *column, const char *value)
{
    int i;
    char sql[1024];
    char *errmsg = NULL;
    if (db == NULL) {
        printf("db is NULL\n");
        return -1;
    }

    sprintf(sql, "insert into %s(%s) values (%s);", sheet, column, value);
    printf("sql: %s\n", sql);

    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg)) {
        printf("sqlite3_exec error: %s\n", errmsg);
        sqlite3_free(errmsg);
        return -1;
    }

    return SQLITE_OK;
}

int CloseDatabase(sqlite3 *db)
{
    if (db == NULL) {
        return 0;
    }
    return sqlite3_close(db);
}

sqlite3_lib.h代码

#ifndef __SQLITE3_LIB_H__
#define __SQLITE3_LIB_H__

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

enum Sqlite3SyncMode {
    // 在每次写入操作完成之前,会等待数据被写入磁盘后再继续下一步操作。这种模式具有最高的数据完整性和可靠性,但性能会受到一定影响
    SQLITE3_SYNC_MODE_FULL = 0,
    // 在写入操作完成之后,会等待数据被写入磁盘的操作系统缓存中后再继续下一步操作。这种模式在数据完整性和性能之间达到了一种平衡,适用于大多数场景
    SQLITE3_SYNC_MODE_NORMAL,
    // 在写入操作完成后,不会等待数据被写入磁盘,直接继续下一步操作。这种模式具有最高的性能,但数据的完整性和可靠性可能会受到一定影响。适用于对数据完整性要求不高的场景,例如缓存数据
    SQLITE3_SYNC_MODE_OFF
};

struct Sqlite3SyncOps {
    int id;
    char *sql;
};

int CreateDatabase(char *dbname, sqlite3 **db);
int SetDatabaseSync(sqlite3 *db, enum Sqlite3SyncMode mode);
int CreateDataSheet(sqlite3 *db, const char *sql);
int InsertDataValue(sqlite3 *db, const char *sheet, const char *column, const char *value);
int CloseDatabase(sqlite3 *db);

#endif /* end of __SQLITE3_LIB_H__ */

Makefile代码

#************************************************************************
#> File Name: Makefile.c
#> Author: Wenfei6316
#> Mail: wen_fei@hoperun.com 
#> Created Time: 2024年07月1日 星期一 03时44分36秒
#************************************************************************

sqlite3_lib:
    gcc sqlite3_lib.c -fPIC -shared -o libsqlite3_lib.so


all: sqlite3_lib ECHO
    gcc main.c -o main -lsqlite3 -L./ -lsqlite3_lib

ECHO:
    @echo $(SUBDIR)
    @echo "========>begin compile"    
    
clean:
    find ./ -name "*.o" -exec rm {} \;

六、Demo样例

6.1 dictory创建

#include "sqlite3_lib.h"

#define CREATE_TABLE "create table if not exists dict(word text primary key, translation text);"

int main(int argc, char **argv)
{
    int i;
    int cnt = 1;
    int ret;
    FILE *fp = NULL;
    sqlite3 *db = NULL;
    char buf[1024] = {0};
    char value[1024] = {0};
    printf("start create database\n");
    // 1. 创建数据库
    ret = CreateDatabase("dictionary.db", &db);
    if (ret != SQLITE_OK) {
        printf("CreateDatabase error: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 2. 设置数据库同步模式
    ret = SetDatabaseSync(db, SQLITE3_SYNC_MODE_FULL);
    if (ret != SQLITE_OK) {
        printf("SetDatabaseSync error: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 3. 常见表格
    ret = CreateDataSheet(db, CREATE_TABLE);
    if (ret != SQLITE_OK) {
        printf("CreateDataSheet error: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 4. 插入数据
    fp = fopen("dict.txt", "r");
    if (fp == NULL) {
        printf("open dict.txt error\n");
        return -1;
    }

    while (fgets(buf, sizeof(buf), fp) != NULL) {
        if (buf[strlen(buf)-1] == '\n') {
            buf[strlen(buf)-1] = '\0';
        }

        // 获取单词结尾地方并设置为\0, 以及翻译起始位置
        for (i = 0; buf[i] != ' '; i++);
        buf[i] = '\0';
        for(; buf[++i] == ' ';);

        // 插入数据到数据库
        snprintf(value, 1024, "\"%s\", \"%s\"", &buf[0], &buf[i]);
        printf("%d: value: %s\n", cnt++, value);
        ret = InsertDataValue(db, "dict", "word, translation", value);
        if (ret != SQLITE_OK) {
            printf("InsertDataValue error: %s\n", sqlite3_errmsg(db));
            return -1;
        }

        memset(buf, '\0', sizeof(buf));
        memset(value, '\0', sizeof(value));
    }

    fclose(fp);
    CloseDatabase(db);
    printf("close database success\n");
    return 0;
}

附录

另有Python简单封装的sqlite3操作可参见 itopen组织: module_code

上一篇:Java-List集合堆内存溢出-情况一


下一篇:基于Hadoop平台的电信客服数据的处理与分析④项目实现:任务18: 数据展示