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就是降序。

SELECTselect_list
FROMtable
ORDER BYcolumn_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.mzph.cn/news/771908.shtml

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

相关文章

Web UI 自动化测试方案(超级干货)看完不会你找我

项目讨论 一、项目中符合自动化测试的部分有哪些&#xff1f;(目标和范围 scope&#xff0c; 准入准出标准) 1、稳定的需求点、变动较少的页面 2、每日构建后的测试验证 daily build 3、比较频繁的回归测试 4、需要在多平台上运行的相同测试案例、组合遍历型的测试、大量的重…

what is apache?

Apache 通常指 Apache Software Foundation (ASF) 或 Apache HTTP Server&#xff0c;两者都是计算机软件领域的重要实体。 Apache 软件基金会 (ASF)&#xff1a;Apache 软件基金会是一个开发开源软件项目的非营利组织。它为涵盖软件开发各个方面的广泛项目提供支持&#xff0c…

3dmax展厅异形模型怎么做---模大狮模型网

在3ds Max中创建展厅异形模型需要一定的建模技巧和创造力。以下是一般的步骤&#xff1a; 准备设计方案&#xff1a; 首先&#xff0c;需要明确展厅的设计方案和概念&#xff0c;包括展厅的整体结构、空间布局和异形特点等。 创建基本结构&#xff1a; 在3ds Max中&#xff…

MySQL数据库的备份-恢复-日志

一、备份&#xff1a; 1.数据备份的重要性&#xff1a; 备份的主要目的是灾难恢复。 在生产环境中&#xff0c;数据的安全性至关重要。 任何数据的丢失都可能产生严重的后果。 2.造成数据丢失的原因&#xff1a; 程序错误人为操作错误运算错误磁盘故障灾难&#xff08;如…

30岁失业的我,选择职场转型,进入AIGC工程师领域,重新开始

去年&#xff0c;刚满30岁的我又一次被公司辞退了&#xff0c;由于学历不高&#xff0c;简历也不出彩&#xff0c;尽管半个月来投了一份又一份的简历&#xff0c;但仍然是石沉大海&#xff0c;我终于不得不开始思考一个以前被我一直刻意压制的想法——职场转型。 尽管知道这条…

大模型知识点汇总——分布式训练

PS&#xff1a;本篇只在宏观上介绍相关概念和技术&#xff0c;不做数学推导和过于细节介绍&#xff0c;旨在快速有一个宏观认知&#xff0c;不拘泥在细节上&#xff0c;导致很混乱。 涉及技术名词 分布式框架等涉及的技术名词很多&#xff0c;很容易让人眼花缭乱&#xff0c;…

echarts 柱形图如何让其中一个柱子的颜色跟其他柱子不同

如何让其中一个柱子的颜色跟其他柱子不同 series: [{data: [120,// 使用对象的形式&#xff0c; value代表当前值, itemStyle设置样式{value: 200,itemStyle: {color: #a90000}},150,80,70,110,130],type: bar}]设置单个柱子颜色&#xff1a; 柱形图单个柱子颜色: https://e…

Vue3+Element Plus+TS开发企业管理后台(二)

使用vite初始化项目 确保你的开发环境中已经安装了Node.js&#xff0c;而且有npm&#xff0c;yarn等包管理工具&#xff0c;然后可以按照vite官方提供的方式初始化项目&#xff1a; yarn create vite跟随提示选择即可&#xff1a; 或者可以直接克隆下面的仓库 https://gith…

flask_restful规范返回值之参数设置

设置重命名属性和默认值 使用 attribute 配置这种映射 , 比如&#xff1a; fields.String(attributeusername) 使用 default 指定默认值&#xff0c;比如&#xff1a; fields.String(defaultsxt) from flask import Flask,render_template from flask_restful import A…

selenium自动化测试-unittest框架

unittest框架的优点 (1)能够组织多个用例去执行 (2)提供丰富的断言方法 (3)能够生成测试报告 unittest框架的核心要素 1. TestCase测试用例 TestCase(测试用例)&#xff0c;最小的测试单元&#xff0c;创建的测试类需要继承该基类 步骤&#xff1a; &#xff08;1&#x…

风丘EV能量流测试解决方案 提高电动汽车续航能力

电动汽车&#xff08;EV&#xff09;近些年发展迅猛&#xff0c;已被汽车业内普遍认为是未来汽车发展的新方向&#xff0c;但现如今电动汽车仍然存在一些短板&#xff0c;导致其还无法替代传统燃油车。对此&#xff0c;首先想到的肯定就是电动车的续航问题。其实解决电动车续航…

VBA技术资料MF133:隐藏编辑栏及计算字符串

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

centos7 使用docker安装了mongo 怎么设置远程链接,必须使用密码才能连接

docker run -d –name mongodb_container -e MONGO_INITDB_ROOT_USERNAMEroot -e MONGO_INITDB_ROOT_PASSWORDroot -e MONGO_INITDB_DATABASEdataserver -p 27017:27017 \ 无法在mongo容器里编辑文件 如果你无法直接编辑 MongoDB 容器内的配置文件&#xff0c;你可以尝试…

基于java+springboot+vue实现的大学生二手物品交易商城(文末源码+Lw+ppt)23-329

摘 要 二十一世纪我们的社会进入了信息时代&#xff0c;信息管理系统的建立&#xff0c;大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多&#xff0c;而在线管理系统刚好能满足这些需求&#xff0c;在线管理系统突破了传统管理方式的局限性。于是本文针对这…

Java:包装类简单认识泛型

一、包装类 包装类指的是基本数据类型&#xff08;如int、double等&#xff09;对应的类类型&#xff0c;我们可以通过包装类直接调用里面的方法&#xff01; 基本数据类型 包装类 byte Byte short …

09 网络ARP请求,响应,ICMP协议

arp协议_arp请求_arp回应 ICMP包构造ping搜狐服务器参考 #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <linux/if_packet.h> #include <linux/if_ether.h> #include <string.h> #includ…

基于Springboot Vue医院管理系统+数据库脚本+文档(万字)

项目效果视频: 基于Springboot Vue医院管理系统 一、 项目介绍 角色&#xff1a;管理员、患者、医生 基于springboot vue实现的医院管理系统&#xff0c;有管理员、医生和患者三种角色。系统拥有丰富的功能&#xff0c;能够满足各类用户的需求&#xff0c;系统提供了登录和注册…

Day20 代码随想录(1刷) 二叉树

目录 654. 最大二叉树 617. 合并二叉树 700. 二叉搜索树中的搜索 98. 验证二叉搜索树 654. 最大二叉树 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数…

最长公共子序列、LCS算法模型

LCS问题就是给定两个序列A和B&#xff0c;求他们最长的公共子序列。 在求解时&#xff0c;我们会设dp[i][j]表示为A[1 ~ i]序列和B[1 ~ j]序列中&#xff08;不规定结尾&#xff09;的最长子序列的长度。 if(a[i]b[i]) dp[i][j]dp[i-1][j-1]1; else dp[i][j]max(dp[i-1][j],dp…

白话模电:4.耦合、差分、无源滤波、反馈(考研面试常问问题)

一、介绍一下三极管多级放大电路的三种耦合方式及其特点&#xff1f;耦合的目的是什么&#xff1f; 多级放大电路中各放大级之间的连接方式称为耦合方式。常见的耦合方式有三种&#xff1a;阻容耦合&#xff08;RC耦合&#xff09;、直接耦合和变压器耦合。 耦合的目的是将信号…