C语言与sqlite3入门

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系列函数

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

打造稳健测评体系:亚马逊测评的关键环节解析

亚马逊测评&#xff0c;简而言之&#xff0c;便是通过真实的购买体验&#xff0c;对产品进行的客观评价。这种评价不仅为卖家提供了产品优化的方向&#xff0c;更为消费者提供了决策的依据&#xff0c;使得产品得以在市场中脱颖而出。然而&#xff0c;现今许多卖家选择自主管理…

ideaSSM 财务凭证管理系统bootstrap开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 idea 开发 SSM 财务凭证管理系统是一套完善的信息管理系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff…

LeetCode540 有序数组中的单一元素

Leetcod540 有序数组中的单一元素 1.题目描述 2.解题思路 同样是二分搜索&#xff0c;利用当i为偶数时候&#xff0c;数组中单独元素左侧的所有i位置与i1位置的数字相同&#xff0c;而单独元素右侧的所有i位置与i1位置元素不同的特性&#xff0c;来进行二分搜索 3.算法思路 …

Java多线程(进阶)

文章目录 目录 文章目录 前言 一 . 常见的锁策略 乐观锁 VS 悲观锁 读写锁 轻量级锁 VS 重量级锁 自旋锁 VS 挂起等待锁 公平锁 VS 非公平锁 可重入锁 VS 不可重入锁 二 . 死锁 死锁的三种典型情况 死锁产生的必要条件 死锁的解决办法 三 . CAS ABA问题 四. S…

Kubernetes(k8s)集群健康检查常用的五种指标

文章目录 1、节点健康指标2、Pod健康指标3、服务健康指标4、网络健康指标5、存储健康指标 1、节点健康指标 节点状态&#xff1a;检查节点是否处于Ready状态&#xff0c;以及是否存在任何异常状态。 资源利用率&#xff1a;监控节点的CPU、内存、磁盘等资源的使用情况&#xf…

“破茧”的快手,何日“成蝶”?

文&#xff5c;小 氿 编&#xff5c;黄小艺 快手&#xff0c;走过了至暗时刻。 3月20日&#xff0c;快手发布2023年第四季度及全年业绩财报。财报显示&#xff0c;2023年快手年营收首次突破千亿元&#xff0c;达到1134.7亿元&#xff0c;同比增长20.5%&#xff1b;而在盈利…

堆排序详解

了解堆的操作和向上&#xff08;下&#xff09;调整算法可以看我的上一篇文章&#xff1a; 详解&#xff08;实现&#xff09;堆的接口函数 文章目录 堆是什么&#xff1f;堆排序的原理如何建堆&#xff1f;怎样建堆更快&#xff1f;1.使用向上调整算法建堆时间复杂度分析 2.使…

CSS的特殊技巧

1.精灵图 使用精灵图核心总结&#xff1a; 1. 精灵图主要针对于小的背景图片使用。 2. 主要借助于背景位置来实现--- background-position 。 3. 一般情况下精灵图都是负值。&#xff08;千万注意网页中的坐标&#xff1a; x轴右边走是正值&#xff0c;左边走是负值&#xf…

抖音小店怎么定类目?分享几个爆单几率大,适合新手的细分类目!

大家好&#xff0c;我是电商糖果 做电商的应该经常听过这么一句话&#xff0c;类目大于一切&#xff01; 好的类目可以让商家减少很多竞争和难题。 糖果做电商有很多年了&#xff0c;我一直认为做店前期最难的定类目&#xff0c;中期是选品&#xff0c;后期是维护店铺。 如…

公司调研 | 空间机械臂GITAI | 日企迁美

最近做的一些公司 / 产品调研没有从技术角度出发&#xff0c;而更关注宏观发展&#xff1a;主营方向、产品介绍、商业化落地情况、融资历程、公司愿景、创始人背景等。部分调研放在知乎上&#xff0c;大部分在飞书私人链接上 最近较关注人形Robot的发展情况&#xff0c;欢迎感兴…

【c++入门】引用,内联函数,auto

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本节我们来到c中一个重要的部分&#xff1a;引用 目录 1.引用的基本概念与用法1.1引用特性1.2使用场景1.3传值、传引用效率比较1.4引用做返回值1.5引用和指针的对…

手撕算法-买卖股票的最佳时机(买卖一次)

描述 分析 只能买卖一次。希望在最低处买&#xff0c;最高处卖。 怎么判断最低处&#xff1f;遍历时存储已遍历的最小值。 怎么判断最高处&#xff1f;遍历时&#xff0c;比较当前位置和最小值的差&#xff0c;取较大的。 代码 class Solution {public int maxProfit(int…

Anaconda安装教程

简介 Anaconda是一个开源的Python发行版&#xff0c;专注于科学计算领域。它支持Linux&#xff0c;Mac&#xff0c;Windows系统&#xff0c;并提供了包管理与环境管理的功能。Anaconda利用工具conda来进行package和environment的管理&#xff0c;并且已经包含了Python和相关的…

SpringCloud从入门到精通速成(二)

文章目录 1.Nacos配置管理1.1.统一配置管理1.1.1.在nacos中添加配置文件1.1.2.从微服务拉取配置 1.2.配置热更新1.2.1.方式一1.2.2.方式二 1.3.配置共享1&#xff09;添加一个环境共享配置2&#xff09;在user-service中读取共享配置3&#xff09;运行两个UserApplication&…

若依用户信息数据导入时自定义密码

若依导入功能: 在使用若依脚手架时,用户信息管理是非常必要的一个部分,而面对大量数据时,使用excel批量导入数据可大大提高效率。若依脚手架也是提供了导入功能,如下图所示: 问题描述 虽然若依脚手架提供了批量导入功能,但其导入的密码总是123456,不仅不安全,而且在…

【Python + Django】静态文件的添加

前言&#xff1a; 前一篇文章我们已经学会了怎么用django写文本页面啦&#xff01;&#xff01;&#xff01; 有一说一&#xff0c;这个静态页面是真的丑。 我们总得用一些花花绿绿的东西把这个丑陋的网站给装饰一下吧&#xff01;&#xff01;&#xff01;&#xff01;&…

手撕算法-接雨水

描述 分析 i位置能积累的雨水量&#xff0c;等于其左右两边最大高度的最小值。为了能获取i位置左右两边的最大高度。使用动态规划。两个dp数组&#xff1a; leftMaxrightMax 其中 leftMax[i] 代表i位置左边的最大高度rightMax[i] 代表i位置右边的最大高度 初始状态&#x…

BEVFormer v2论文阅读

摘要 本文工作 提出了一种具有透视监督&#xff08;perspective supervision&#xff09;的新型鸟瞰(BEV)检测器&#xff0c;该检测器收敛速度更快&#xff0c;更适合现代图像骨干。现有的最先进的BEV检测器通常与VovNet等特定深度预训练的主干相连&#xff0c;阻碍了蓬勃发展…

SpringBoot整合ShardingSphere-JDBC 5.3.2 实现读写分离、分库分表。

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 Docker部署MYSQL主从详细教程-阿木木AEcru…

计算机网络:物理层下的传输媒体概览

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…