C语言与sqlite3入门

news2024/10/7 10:22:37

c语言与sqlite3入门

  • 1 sqlite3数据类型
  • 2 sqlite3指令
  • 3 sqlite3的sql语法
    • 3.1 创建表create
    • 3.2 删除表drop
    • 3.3 插入数据insert into
    • 3.4 查询select from
    • 3.5 where子句
    • 3.6 修改数据update
    • 3.7 删除数据delete
    • 3.8 排序Order By
    • 3.9 分组GROUP BY
    • 3.10 约束
  • 4 c语言执行sqlite3
    • 4.1 下载c源码
    • 4.2 cmake编译运行
  • 5 创建或打开数据库
  • 6 sqlite3_exec
  • 7 sqlite3_prepare
    • 7.1 sqlite3_prepare_v2
    • 7.2 sqlite3_bind
    • 7.3 sqlite3_step
    • 7.4 sqlite3_column
    • 7.5 sqlite3_reset
  • 8 读写blob型数据
  • 参考

1 sqlite3数据类型

  1. NULL 空
  2. INTEGER 整形
  3. REAL 浮点
  4. TEXT 文本
  5. BLOB binary large object二进制对象,一般存图像,声音,自定义结构体

2 sqlite3指令

sqlite3 test.db # 打开数据库, 没有就创建

.databases #查看所有的数据库位置。

在这里插入图片描述

3 sqlite3的sql语法

3.1 创建表create

CREATE TABLE COMPANY(
   ID INT PRIMARY KEY     NOT NULL,
   NAME           TEXT    NOT NULL,
   AGE            INT     NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL
);

3.2 删除表drop

DROP TABLE COMPANY;

3.3 插入数据insert into

INSERT INTO COMPANY VALUES (7, 'James', 24, 'Houston', 10000.00 );

或者

INSERT INTO COMPANY(id, name, age, address, salary) VALUES (7, 'James', 24, 'Houston', 10000.00 );

用第二种更严谨一些
假如没有设置值,为NULL或者0

INSERT INTO COMPANY(ID, name, age) VALUES (8, '张三', 11);

3.4 查询select from

SELECT ID, NAME, SALARY FROM COMPANY ;

3.5 where子句

select * fromwhere name like 'a%'都是会查询所有表的内容,一般禁用。

逻辑与或子句

 SELECT * FROM COMPANY WHERE AGE >= 25 OR SALARY >= 65000

不为空
查询age不为空的记录

SELECT * FROM COMPANY WHERE AGE IS NOT NULL

模糊查询
所有名字以ki开头的

SELECT * FROM COMPANY WHERE NAME LIKE 'Ki%';

in
年龄为25或27的记录

SELECT * FROM COMPANY WHERE AGE IN ( 25, 27 );

年龄不为25且不为27

SELECT * FROM COMPANY WHERE AGE NOT IN ( 25, 27 );

子查询
年龄大于所有65000薪水以上员工年龄的记录

SELECT * FROM COMPANY   WHERE AGE > (SELECT AGE FROM COMPANY WHERE SALARY > 65000);

3.6 修改数据update

UPDATE COMPANY SET ADDRESS = 'Texas' WHERE ID = 6;

3.7 删除数据delete

DELETE FROM COMPANY WHERE ID = 7;

3.8 排序Order By

其实默认就是升序,ASC是升序,DESC就是降序。

SELECT
   select_list
FROM
   table
ORDER BY
    column_1 ASC,
    column_2 DESC;

3.9 分组GROUP BY

比如可以按照年龄来分组,看看不同年龄的平均薪资。

SELECT AGE, avg(SALARY) from  COMPANY GROUP BY AGE;

在这里插入图片描述

3.10 约束

CREATE TABLE COMPANY(
   ID INT PRIMARY KEY     NOT NULL,
   NAME           TEXT    NOT NULL UNIQUE,
   AGE            INT     NOT NULL CHECK(AGE > 0),
   ADDRESS        CHAR(50),
   SALARY         REAL    DEFAULT 50000.00
);

主键约束:PRIMARY KEY,ID作为主键,不能有重复值,一般也不能为NULL。

NOT NULL: 不为空,该列不能有NULL

CEHCK 添加修改记录时,需要符合check条件。

DEFAULT 设置默认值。

4 c语言执行sqlite3

4.1 下载c源码

打开 c源码sqlite3下载页面 下载其中的source code源码,下第一个就好。
在这里插入图片描述
放入项目的sqlite文件夹中,除开我已经创建的两个数据库,项目结果应该长这样。
在这里插入图片描述
随便写一个c,获取sqlite3版本

#include <stdio.h>
#include "sqlite3.h"
int main(void)
{
    printf("%s\n", sqlite3_libversion());

    return 0;
}

4.2 cmake编译运行

在CMakeLists.txt中写

cmake_minimum_required (VERSION 3.5)

project(test)
add_definitions("-Wall -g")

include_directories (sqlite)

add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/test.c ${PROJECT_SOURCE_DIR}/sqlite/sqlite3.c)
target_link_libraries (${PROJECT_NAME} pthread dl)

add_executable(sqliteShell ${PROJECT_SOURCE_DIR}/sqlite/shell.c ${PROJECT_SOURCE_DIR}/sqlite/sqlite3.c)
target_link_libraries (sqliteShell pthread dl)

写好后cd打开build文件夹执行cmake和makefile

cmake .. & make
# 再执行test
./test

在这里插入图片描述
假如没有修改文件结构(增删文件/修改文件位置),只是修改了文件内容。
再次编译代码不需要再次运行cmake了,运行make即可

make
./test

5 创建或打开数据库

sqlite3_open函数,打开数据库,没有就创建一个。

第一个参数就是数据库位置,相对位置是相对于程序执行时的位置,不是c文件所在位置
第二个是双指针的通道

sqlite3 *db = NULL;
int rc = sqlite3_open("../test.db", &db);

关闭

sqlite3_close(db);

如下方就可以创建一个表,并且插入一些值来使用

#include <stdio.h>
#include "sqlite3.h"
int main(void) 
{
    sqlite3 *db = NULL;
    char *err_msg = NULL;
    int rc = sqlite3_open("../test.db", &db);

    if(rc != SQLITE_OK){
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }
    const char *sql = "DROP TABLE IF EXISTS Cars;" 
                      "CREATE TABLE Cars(Id INT, Name TEXT, Price INT);" 
                      "INSERT INTO Cars VALUES(1, 'Audi', 52642);" 
                      "INSERT INTO Cars VALUES(2, 'Mercedes', 57127);" 
                      "INSERT INTO Cars VALUES(3, 'Skoda', 9000);" 
                      "INSERT INTO Cars VALUES(4, 'Volvo', 29000);" 
                      "INSERT INTO Cars VALUES(5, 'Bentley', 350000);" 
                      "INSERT INTO Cars VALUES(6, 'Citroen', 21000);" 
                      "INSERT INTO Cars VALUES(7, 'Hummer', 41400);" 
                      "INSERT INTO Cars VALUES(8, 'Volkswagen', 21600);";
    rc = sqlite3_exec(db, sql, NULL, NULL, &err_msg);

    if(rc != SQLITE_OK){
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
        sqlite3_close(db);

        return 1;
    }
    sqlite3_close(db);
    return 0;

}

6 sqlite3_exec

sqlite3_exec是执行sql语句的函数,算是最重要的函数。

sqlite3*, //数据库
const char* sql,//sql语句
*callback, //回调
void* data, //回调的参数  
char **errmsq //错误信息
const char * = "SELECT * FROM car";
char* dataName = "test";
char *err_msg = NULL;
int rc = sqlite3_exec(db, sql, callback, dataName, &err_msg);

int callback(void* para, int columnCount, char** columnValue, char** columnName){}

callback在每查询到一行数据的时候就调用一次,所以每次得到的是一行数据。

其中callback只能自己传一个参数,但是自身有4个参数。

  1. para 传来的参数
  2. columnCount 列数
  3. columnValue 一维的字符串数组,保存的是每一列数据。
  4. columnName 一维字符串数组,列名。

比如下方获取所有的test.db中的数据,打印出来。

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

int callback(void *, int, char **, char **);


int main(void)
{
    sqlite3 *db = NULL;
    char *err_msg = NULL;

    int rc = sqlite3_open("../test.db", &db);
    if (rc != SQLITE_OK) {
        
        fprintf(stderr, "Cannot open database: %s\n", 
                sqlite3_errmsg(db));
        sqlite3_close(db);
        
        return 1;
    }

    const char *sql = "SELECT * FROM Cars";
    char* dataName = "test";
    rc = sqlite3_exec(db, sql, callback, dataName, &err_msg);
    if (rc != SQLITE_OK ) {
        
        fprintf(stderr, "Failed to select data\n");
        fprintf(stderr, "SQL error: %s\n", err_msg);

        sqlite3_free(err_msg);
        sqlite3_close(db);
        
        return 1;
    }

    sqlite3_close(db);

    return 0;
}

int callback(void* para, int columenCount, char** columnValue, char** columnName)
{

    for (int i = 0; i < columenCount; ++i)
    {
        printf("%s = %s\n", columnName[i], (columnValue[i] ? columnValue[i] : "NULL"));
    }

    printf("\n");

    return 0;
}

7 sqlite3_prepare

exec使用起来简单,它在执行的过程中,有一个编译再执行的过程。
假如有多个insert语句,exec需要每inset一次都需要编译一次,效率低。
对于结构相同的语句,我们是否可以先编译,于是有了一个prepare,先编译,再插入变量执行。

最开始有一个控制变量sqlite3_stmt的句柄,其中stmt的全称应该是statement。

sqlite3_stmt *pstmt;

7.1 sqlite3_prepare_v2

先需要准备一个模板

int sqlite3_prepare_v2(
    sqlite3 *db,            /* 数据库通道 */
    const char *zSql,       /* sql语句 */
    int nByte,              /* sql语句长度,一般填入-1自动计算 */
    sqlite3_stmt **ppStmt,  /* 准备语句的控制权柄 */
    const char **pzTail     /* sql语句超出了nByte后存放位置,一般把nByte设置足够大,这个设置为NULL即可 */
);

下面是一个模板的代码,将插入语句设置为模板,其中需要插入的内容用?代替

sqlite3_stmt *pStmt = NULL;
char *pzTail = NULL;
const char *sql = "INSERT INTO person(name, age, sex) VALUES(?,?,?);";
rc = sqlite3_prepare_v2(pdb, sql, strlen(sql), &pStmt, pzTail);

用prepare语句后可以先编译。

7.2 sqlite3_bind

这个函数就是设置插入值。

有三个函数,用于插入不同类型值。

int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_doubule(sqlite3_stmt*, int, double);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int, void(*)(void*));
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int, void(*)(void*))
  1. 句柄handle
  2. 需要赋值的是sql语句中的第几个参数,从1开始。
  3. 插入值,text和blob是指针。
  4. 插入值长度(strlen/sizeof)。
  5. 绑定blob类型的析构函数,一般可以设置为NULL

那么现在我们需要插入值来形成一个sql语句就可以这么写

const char * name = "iceylia";
age = 100;
sex = "未知";
sqlite3_bind_text(pstmt, 1, name, strlen(name), NULL);
sqlite3_bind_int(pstmt, 2, age);
sqlite3_bind_text(pstmt, 3, sex, strlen(sex), NULL);

7.3 sqlite3_step

插入值后执行sql语句,用sqlite3_step

rc = sqlite3_step(pstmt);

返回值有两个需要注意的返回值

  1. SQLITE_DONE: 表示执行完毕
  2. SQLITE_ROW: 当使用select语句时,会得到多个数据,每次只能读取一行的值,

比如获取表中所有参数,需要多次使用sqlite3_step获取列。

const char *sql = "SELECT * FROM Cars;";
const char *pzTail;
rc = sqlite3_prepare_v2(db, sql, -1, &pStmt, &pzTail);
while(sqlite3_step(pStmt)==SQLITE_ROW){
    printf("id = %d\n", sqlite3_column_int(pStmt, 0));
}

在这里插入图片描述

7.4 sqlite3_column

上面的示例代码中使用了sqlite3_column,这是获取查询到的数据的函数

同样有三个,第二个参数是列号,从0开始。

int sqlite3_column_int(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);

7.5 sqlite3_reset

将bind绑定的值全部取消清楚,方便重新绑定

int sqlite3_reset(sqlite3_stmt *pStmt);

这么做的目的就是在比如插入多个数据,绑定了一个人的数据,然后需要绑定第二个的时候需要清空statement。

8 读写blob型数据

读入
建表时定义一个blob,插入时用statement插入

const char *newSql = "INSERT INTO Images(Data) VALUES(?)";
rc = sqlite3_prepare_v2(db, newSql, -1, &pStmt, NULL);
sqlite3_bind_blob(pStmt, 1, &data, sizeof(data), NULL);

读取,也用statement读取,用column读取。

myData *pData = (myData*)sqlite3_column_blob(pStmt, 0);

在这里插入图片描述
下面是一个完整的读取写入代码。

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

typedef struct
{
    int value1;
    double value2;
} myData;

int main(void)
{
    sqlite3 *db = NULL;
    char *err_msg = NULL;

    int rc = sqlite3_open("../test.db", &db);
    if (rc != SQLITE_OK)
    {

        fprintf(stderr, "Cannot open database: %s\n",
                sqlite3_errmsg(db));
        sqlite3_close(db);

        return 1;
    }

    const char *sql = "DROP TABLE IF EXISTS Images;"
                      "CREATE TABLE Images(Id INTEGER PRIMARY KEY, Data BLOB);";

    rc = sqlite3_exec(db, sql, NULL, NULL, &err_msg);
    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "Failed to select data\n");
        fprintf(stderr, "SQL error: %s", err_msg);
        sqlite3_free(err_msg);
        sqlite3_close(db);
        return 1;
    }
    sqlite3_stmt *pStmt = NULL;
    const char *newSql = "INSERT INTO Images(Data) VALUES(?)";
    rc = sqlite3_prepare_v2(db, newSql, -1, &pStmt, NULL);
    myData data = {100, 0.156};
    sqlite3_bind_blob(pStmt, 1, &data, sizeof(data), SQLITE_STATIC);
    rc = sqlite3_step(pStmt);
    if (rc != SQLITE_DONE)
    {
        printf("execution failed: %s", sqlite3_errmsg(db));
    }
    sqlite3_finalize(pStmt);
    

    char *sql2 = "SELECT Data FROM Images WHERE Id = 1";

    pStmt = NULL;
    rc = sqlite3_prepare_v2(db, sql2, -1, &pStmt, NULL);
     if (rc != SQLITE_OK ) {
        
        fprintf(stderr, "Failed to prepare statement\n");
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        
        sqlite3_close(db);
        
        return 1;
    } 
    
    rc = sqlite3_step(pStmt);

    int bytes = 0;

    if (rc == SQLITE_ROW)
    {
        bytes = sqlite3_column_bytes(pStmt, 0);
    }

    myData *pData = (myData*)sqlite3_column_blob(pStmt, 0);

    printf("bytes: %d, %d, %lf\n", bytes, pData->value1, pData->value2);

    rc = sqlite3_finalize(pStmt);   

    sqlite3_close(db);

    return 0;
}

参考

C语言操作SQLite3简明教程
深入理解SQLite3之sqlite3_exec及回调函数
玩转SQLite-11:C语言高效API之sqlite3_prepare系列函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1539906.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jmeter使用方法---自动化测试

HTTP信息头管理器 一个http请求会发送请求到服务器&#xff0c;请求里面包含&#xff1a;请求头、请求正文、请求体&#xff0c;请求头就是信息头Authorization头的主要用作http协议的认证。 Authorization的作用是当客户端访问受口令保护时&#xff0c;服务器端会发送401状态…

Head First Design Patterns -模板方法模式

什么是模板方法模式 在一个方法中定义一个算法的骨架&#xff0c;而把一些步骤延迟到子类。模板方法使得子类可以在不改变算法结构的情况下&#xff0c;重新定义算法的某些步骤。 这些算法步骤中的一个或者多个被定义为抽象的&#xff0c;由子类实现。 类图 代码 书中用泡茶和…

鸿蒙开发实战:网络请求库【axios】

简介 [Axios] &#xff0c;是一个基于 promise 的网络请求库&#xff0c;可以运行 node.js 和浏览器中。本库基于[Axios]原库v1.3.4版本进行适配&#xff0c;使其可以运行在 OpenHarmony&#xff0c;并沿用其现有用法和特性。 http 请求Promise APIrequest 和 response 拦截器…

分布式ID生成方案总结

分布式场景下&#xff0c;由于通常是分库分表&#xff0c;所以通常无法仅仅使用数据库的自增Id。需要使用其他方案生成唯一的id。目前业界主流的是基于雪花算法或者雪花算法的改进版本。 UUID 有什么特点&#xff1f; 足够的简单&#xff0c;java原生自带。本地生成具有唯一性…

kubernetes负载均衡-service

一、service的概念 1、什么是service 在Kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;当我们需要访问这个应用时&#xff0c;可以通过Pod的IP进行访问&#xff0c;但是这里有两个问题:1、Pod的IP地址不固定&#xff0c;一旦Pod异常退出、节点故障&#xff0c;则会…

java的IO之NIO

NIO是一种同步非阻塞的I/O模型&#xff0c;在Java 1.4中引入了NIO框架&#xff0c;对应java.nio包&#xff0c;提供了channel、selector、buffer等。 NIO中的N可以理解为Non-blocking不在单纯是New&#xff0c;它支持面向缓冲的&#xff0c;基于通道的I/O操作方法。NIO提供了与…

SCI一区 | Matlab实现WOA-TCN-BiGRU-Attention鲸鱼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测

SCI一区 | Matlab实现WOA-TCN-BiGRU-Attention鲸鱼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现WOA-TCN-BiGRU-Attention鲸鱼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测预测效果基本介绍模型描述程序…

微信小程序 - picker-viewer实现省市选择器

简介 本文会基于微信小程序picker viewer组件实现省市选择器的功能。 实现效果 实现代码 布局 <picker-view value"{{value}}" bindchange"bindChange" indicator-style"height: 50px;" style"width: 100%; height: 300px;" &…

使用Intellij idea编写Spark应用程序(Scala+Maven)

使用Intellij idea编写Spark应用程序(ScalaMaven) 对Scala代码进行打包编译时&#xff0c;可以采用Maven&#xff0c;也可以采用sbt&#xff0c;相对而言&#xff0c;业界更多使用sbt。这里介绍IntelliJ IDEA和Maven的组合使用方法。IntelliJ IDEA和SBT的组合使用方法&#xf…

牛客题霸-SQL篇(刷题记录二)

本文基于前段时间学习总结的 MySQL 相关的查询语法&#xff0c;在牛客网找了相应的 MySQL 题目进行练习&#xff0c;以便加强对于 MySQL 查询语法的理解和应用。 由于涉及到的数据库表较多&#xff0c;因此本文不再展示&#xff0c;只提供 MySQL 代码与示例输出。 以下内容是…

Xilink 简单双口ram ip的读写仿真

简单双口RAM有两个端口Port A和port B,其中Port A用于写数据&#xff0c;Port B用于读数据&#xff0c;读写接口可以独立时钟工作。这一点和真双口RAM是有区别的&#xff0c;真双口RAM的A B两个Port都可以进行读写操作。 RAM是FPGA中重要的数据结构&#xff0c;可用于数…

EI级!高创新原创未发表!VMD-TCN-BiGRU-MATT变分模态分解卷积神经网络双向门控循环单元融合多头注意力机制多变量时间序列预测(Matlab)

EI级&#xff01;高创新原创未发表&#xff01;VMD-TCN-BiGRU-MATT变分模态分解卷积神经网络双向门控循环单元融合多头注意力机制多变量时间序列预测&#xff08;Matlab&#xff09; 目录 EI级&#xff01;高创新原创未发表&#xff01;VMD-TCN-BiGRU-MATT变分模态分解卷积神经…

阿里云4核16G服务器价格26.52元1个月、149.00元半年,ECS经济型e实例

阿里云4核16G服务器优惠价格26.52元1个月、79.56元3个月、149.00元半年&#xff0c;配置为阿里云服务器ECS经济型e实例ecs.e-c1m4.xlarge&#xff0c;4核16G、按固定带宽 10Mbs、100GB ESSD Entry系统盘&#xff0c;活动链接 aliyunfuwuqi.com/go/aliyun 活动链接打开如下图&a…

【数据挖掘】实验4:数据探索

实验4&#xff1a;数据探索 一&#xff1a;实验目的与要求 1&#xff1a;熟悉和掌握数据探索&#xff0c;学习数据质量分类、数据特征分析和R语言的主要数据探索函数。 二&#xff1a;实验内容 1&#xff1a;数据质量分析 2&#xff1a;统计量分析 3&#xff1a;贡献度分析…

【黄啊码】如何用GPT和向量数据库做问答型AI

知识库服务依赖该数据库&#xff0c;Embedding 形式个性化训练 ChatGPT&#xff0c;必不可少的就是向量数据库 因为 qdrant 向量数据库只支持 Docker 部署&#xff0c;所以需要先安装好 Docker 服务。 命令行安装 拉取镜像 docker pull qdrant/qdrant 运行服务 docker run -…

查立得源码如何去除版权

最近发现很多人百度&#xff1a;查立得源码如何去除版权。 每个源代码/软件都是有版权的&#xff0c;无法去除&#xff0c;我们也得尊重知识产权/劳动成果。 可以去除/修改的是&#xff1a;页面显示的版权信息,查立得底部信息均可自定义(一般conn.php可修改)。 另&#xff1…

图床项目实战:后续开发与优化

在之前的文章中&#xff0c;我们介绍了图床项目的基本实现&#xff0c;接下来&#xff0c;我将提供扩展功能和优化性能的关键代码片段。 一、图片分类管理 首先&#xff0c;我们需要在数据库中创建分类表&#xff0c;并在图片表中添加分类字段。 class Category(db.Model): …

STM32---DHT11采集与BH1750FVI光照传感器(HAL库、含源码)

写在前面&#xff1a;本节我们学习使用两个常见的传感器模块&#xff0c;分别为DHT11温湿度传感器以及BH1750FVI光照传感器,这两种传感器在对于环境监测中具有十分重要的作用&#xff0c;因为其使用简单方便&#xff0c;所以经常被用于STM32的项目之中。今天将使用分享给大家&a…

会员中心微服务

文章目录 1.环境配置1.创建会员中心模块2.检查父子模块的pom.xml1.父模块注意&#xff1a;如果父模块中的依赖显示not found&#xff0c;原因是子模块并没有引用&#xff0c;不用在意 2.子模块 3.pom.xml 引入相关依赖&#xff08;别忘记刷新maven&#xff09;4.application.ym…