SQLite3
SQLite 是一款轻量级、文件型、无服务端、零配置的关系型数据库
- 没有独立服务器进程,数据库就是一个后缀
.db的磁盘文件 - 跨平台:Windows / Linux / Mac / 嵌入式 (STM32、树莓派、Android)
- C 语言开发,体积很小,库文件几百 KB
- 不需要账号密码,单文件数据库,适合本地、嵌入式、单机程序
- 不支持高并发写操作;适合客户端、嵌入式、小型项目,不适合网站高并发后台
1. 打开 / 创建数据库
sqlite3 test.db
如果 test.db 不存在,会新建文件;存在就打
开它
2.常用点命令以 . 开头,不是 SQL 语句
除了命令语句,所有的sql语句都要以分号结尾
.help -- 查看帮助
.tables -- 列出所有表
.schema -- 查看所有建表语句
.schema 表名 -- 查看某张表结构
.quit -- 退出
.exit -- 退出
.mode column -- 列对齐显示结果
.headers on -- 打开表头显示
3.创建一个表
create table stu(sno int,name text,score float);
create table为命令格式。stu为表的名字,括号内,以逗号隔开每一个数据列,先写数据名,后写数据类型。数据类型具体如下
| 亲和类型 | 推荐写法 | 实际底层类型 |
|---|---|---|
| TEXT 亲和 | name TEXT、name VARCHAR(32) |
TEXT |
| NUMERIC 亲和 | age NUMERIC、birthday DATE |
优先存数字,也可存字符串 |
| INTEGER 亲和 | id INTEGER、num INT |
INTEGER |
| REAL 亲和 | price REAL、weight FLOAT |
REAL |
| BLOB 亲和 | data BLOB |
BLOB |
4.插入一行数据
insert into stu values(110,'tom',95.7);
insert into 为固定格式,stu为表的名字,valus也是固定格式,括号内数据要按照创建表的时候的格式写,因为这是插入一整行的数据,字符串可以用单引号也可以用双引号。
单独插入一行不全的数据
insert into stu (sno,name) values(110,'tom');
5.查询表内的所有数据
SELECT * FROM stu;
6.按条件查找某一行
SELECT * FROM stu WHERE sno=110;
7.只查部分字段
SELECT name,score FROM stu;
8.模糊查询
SELECT * FROM stu WHERE name LIKE 'tom';
程序内通过函数操作sqlite数据库
打开与关闭数据库,操作与直接操作文件方法相同,直接对应文件名进行打开操作,但sqlite数据库需要定义为sqlite3 *类型的指针进行接收打开的文件描述符
#include <stdio.h>
#include <sqlite3.h>
int main(void)
{
sqlite3 *db;
int ret;
/* 打开数据库,不存在则自动创建 */
ret = sqlite3_open("test.db", &db);
if(ret != SQLITE_OK)
{
printf("打开失败: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return -1;
}
printf("数据库打开成功\n");
sqlite3_close(db);
return 0;
}
执行无返回结果的建表、插入、更新、删除时,使用的函数
int sqlite3_exec(
sqlite3* db, // 数据库句柄
const char *sql, // SQL字符串
int (*callback)(void*,int,char**,char**), // 查询回调函数
void *arg, // 传给回调的自定义参数
char **errmsg // 错误信息输出
);
返回值
SQLITE_OK:成功
其他:失败
用函数操作,向表内插入数据
char sql[][50] ={"insert into user values(110,'tom',123456);","insert into user values(111,'jack',666666);","insert into user values(112,'tom',888888);"};
for(int i = 0;i<3;i++)
{
ret = sqlite3_exec(db,sql[i],NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
printf("sqlite3_exec fail:%s\n",errmsg);
return -1;
}
}
自定义callback回调函数,进行select查询操作
/**
* @brief sqlite3_exec 查询结果回调函数
* @param arg 自定义参数,此处传入表头打印标记变量的地址
* @param columns_num 当前行的字段总数量
* @param value 字符串数组,保存一行记录的数据内容
* @param value_name 字符串数组,保存各个字段的名称(表头)
* @return 返回0,表示回调处理正常结束
*/
int callback(void *arg,int columns_num,char **value,char **value_name)
{
// 将void*通用指针转换为int指针,接收外部传入的表头标记
int *first = (int *)arg;
int i = 0;
// 判断是否为第一次进入回调,只打印一次顶部分割线
if(*first == 1)
{
printf("------------------------------\n");
*first = 0; // 修改标记,后续行不再打印顶部分隔线
}
// 循环打印表头(字段名)
while(i<columns_num)
{
printf("%s\t",value_name[i]);
i++;
}
putchar('\n'); // 表头打印完成后换行
i = 0; // 重置循环下标,准备打印本行数据
// 循环打印当前一行每条字段的数据
while(i<columns_num)
{
printf("%s\t",value[i]);
i++;
}
putchar('\n'); // 当前一行数据打印完毕换行
printf("------------------------------\n"); // 打印行底分隔线
return 0;
}
//调用执行select命令
ret = sqlite3_exec(db,sql,callback,&head,&errmsg);
使用函数sqlite3_get_table直接查询表内容,无需定义callback
// 定义sqlite3数据库句柄,初始化为空
sqlite3 *db = NULL;
// 打开(不存在则创建)test.db数据库,数据库句柄存入db
int ret = sqlite3_open("test.db",&db);
// 判断打开是否失败,SQLITE_OK代表成功
if(ret != SQLITE_OK)
{
printf("sqlite3_open fail\n");
return -1;
}
char *errmsg; // 错误信息字符串指针
char **result; // 存放查询结果的二维字符串数组
int row; // 查询结果的数据行数(不包含表头字段名)
int col; // 查询结果的列数(字段数量)
// sqlite3_get_table:执行SQL查询,结果存入result
// 参数依次:数据库句柄、sql语句、结果缓冲区、行数、列数、错误信息
ret = sqlite3_get_table(db,"select * from user;",&result,&row,&col,&errmsg);
// SQL执行失败判断
if(ret != SQLITE_OK)
{
printf("sqlite3_exec fail:%s\n",errmsg);
return -1;
}else
{
int i = 0;
// 打印表头:result数组最前面存放的是每一列的字段名
for(i=0;i<col;i++)
{
printf("%s\t",result[i]);
}
putchar('\n'); // 表头打印完成后换行
// 循环遍历每一行数据
for(int j = 0;j<row;j++)
{
// 打印一行里面的每一列单元格数据
for(int n = 0;n<col;n++)
{
printf("%s\t",result[i]);
i++; // 数组下标向后偏移,取下一条数据
}
putchar('\n'); // 一行打印结束换行
}
// 释放sqlite3_get_table自动分配的结果内存,必须调用,否则内存泄漏
sqlite3_free_table(result);
}
关闭已经打开的数据库文件
sqlite3_close(db);