一、QSLite的优势和应用场景
1.优势
- 轻量级和高效:
- SQLite 的代码库非常小,通常只有几百 KB,适合嵌入式系统和移动应用。
- 由于其高效的实现,SQLite 的性能在许多应用中都非常优秀。
- 无需服务器和配置
- SQLite 是一个服务器进程,数据库文件直接存储在磁盘上,不需要单独的数据库服务器进程或配置。
- 跨平台
- SQLite 支持多种操作系统,包括 Windows、Linux、macOS、iOS 和 Android,确保了应用程序的跨平台兼容性。
- 灵活的数据类型:
- 支持多种数据类型,包括整数、浮点数、文本、二进制数据等,且可以通过 SQL 语句进行复杂的数据操作。
2.应用场景
- 移动应用开发
- SQLite 是许多移动操作系统的默认数据库,适用于 iOS 和 Android 应用程序的本地存储。支持数据库大小至2TB
- 桌面应用程序:
- 许多桌面应用程序,如文本编辑器、图像编辑软件等,使用 SQLite 作为其本地数据库,简化数据管理。
- 嵌入式系统
- 由于其小巧的特性,SQLite 非常适合嵌入式设备,如家庭自动化系统、智能家居设备和汽车娱乐系统。
- 测试和开发:
- SQLite 是开发和测试环境中非常流行的数据库,方便开发者在不需要复杂数据库服务器的情况下进行数据测试和调试。比目前流行的大多数数据库对数据的操作要快;
二、安装
- 虚拟机联网
- 步骤(linux终端下)
- sudo apt-get update //update 命令用来更新软件包列表,以便系统知道有哪些软件包可以安装或升级。
- sudo apt-get install sqlite3//安装 SQLite3 数据库软件。
- sudo apt-get install libsqlite3-dev//安装 SQLite3 的开发支持库。这些库包括 SQLite3 的头文件和库文件,供开发人员在编译程序时使用。
- sudo apt-get install sqlitebrowser//安装 SQLite3 数据库的图形用户界面操作软件 DB Browser for SQLite(以前称为 SQLiteBrowser)。这个工具可以用来以图形方式浏览、管理和编辑 SQLite 数据库文件。使用方法为sqlitebrowser 数据库名(加后缀);
- 判断安装是否成功,输入sqlite3 my.db出现sqlite3>即可
三、sqlite3命令语句
- 命令不区分大小写
1.创建数据库或链接到数据库
sqlite3 database_name.db
- database_name.db: 这是你要连接的数据库文件的名称。如果该文件不存在,SQLite 会自动创建一个新的数据库文件。
2.系统命令(也称为点命令)
.quit
---------------->退出数据库.exit
---------------->退出数据库.help
--------------->显示帮助信息,获取所有系统命令.tables
-------------> 查看当前数据库下的所有表格.schema
----------->查看表的结构,显示指定表的创建语句,包括列定义和任何索引。
.databases
----->列出所有已连接的数据库及其路径名。
3.sql语句
- sql的命令以“;”结尾,因此可以写多行。
- 创建表格
//创建stu这个表格,id和name是字段名,数据类型在字段名后面
//数据类型在字段名后面定义是为了明确指定该字段可以存储的数据的类型和特性。这种语法约定使得数据库管理系统能够正确地分配存储空间并执行数据验证
create table stu(id int,name char);
//IF NOT EXISTS:这个子句确保只有在表 stu 不存在时才会创建该表。如果表 stu 已经存在,则不会创建新的表,从而避免错误。
//if not exists可以在很多语句中使用。
create table if not exists stu(id int,name char);
//创建表格时,可以设置默认值,因此在插入记录时,如果没有提供值,默认值将被使用
create table stu (id int,name char ,default "Unknown");
//检查约束,确保列中的值满足特定的条件
create table stu (id int,name char,age int,check(age>0));
- 删除表格
drop table 表名;
eg
drop table stu1;
- 插入记录
- 全字段插入(即每一列都有数据)
insert into 表名 values(数据1,数据2);
eg:insert into stu values(001,"张三");
- 部分字段插入
insert into 表名(字段1,字段2) values(数据1,数据2);
eg:insert into stu(name) values("李四");
//数据的顺序要与指定的字段名1,字段2对应。
- 查看记录
.header on
打开表头,查看记录时会给出字段那一行。如id,name
。.header off
关闭表头select* from 表名;
//查看该表的所有内容- 查看特定几行
select* from 表名 where 限制条件 LIMIT 1;
//限制条件可以使用and 和or 组合
// limit 1 查看前1行数据,也可以不写,则默认全部。
//limit 5 offset 6 从符合条件的第6行开始,显示5行数据。offset有偏离的意思
eg: select * from stu where id<2 or id>3;
select * from my.db where id in(1,3,5);
//这个查询将返回 id 值为 1、3 和 5 的行。
SELECT * FROM my_table
WHERE some_column = 'some_value'
LIMIT 10;//这个查询将返回 some_column 列值为 'some_value' 的前 10 行数据。
- 查看某几列
select 字段1, 字段2 from 表名;
select 字段1,字段2 from 表明 where 限制条件;
//其实语句中的*可以看成包含了所有的字段,查看某几列时又单独列出来
- 修改记录
update 表名 set 字段=数值 where 限制条件;
update stu set score=60 where id=1;
-
删除记录
delete from 表名 where 限制条件;
delete from stu where id=1;
delete from stu;//删除表格中所有的数据。 -
主键(primary key)
- 键保证表中每一行的数据都有一个唯一标识。这意味着主键字段的值在同一表中不能重复,每条记录都可以通过其主键值来唯一定位。
- 索引:主键自动成为表的索引。该索引通常是一个数组的数据结构,使得数据的查找、更新和删除更加快速。对主键列的查询比对非索引列的查询要快。
- 一张表只能有一个主键
create table 表名(字段名 数据类型 primary key,字段名 数据类型);
eg:
create table 表名(id int primary key,name char,score float);
- 拷贝
从a中拷贝所有数据到b中:
create table b as select * from a;//a 可以看成包含所有的字段
从a中拷贝指定字段到b中:
create table b as select 字段,字段 from a;
create table stu1 as select id,name from stu;
- 修改表中的内容
- 增加列
alter table 表名 add column 字段名 数据类型;
eg:
alter table stu add column score int;
- 修改表名
alter table 旧表明 rename to 新表名;
alter table stu rename to stuinfo;
- 删除列
不支持直接删除列- 创建一个新表,并复制旧表a需要保留的字段信息;
create table stu as select name,age1,sex from stuinfo; - 删除旧表
drop table stuinfo; - 修改新表的名字
alter table stu rename to stuinfo;
- 创建一个新表,并复制旧表a需要保留的字段信息;
- 修改字段名(列名)
不支持直接修改列名- 将表重新命名(a改成b)
alter table stuinfo rename to stu; - 新建修改名字后的表(新建一个a)
create table stuinfo (name char,age1 int,sex char, score int); - 从旧表中提取数据,插入到新表中。
insert into stuinfo select * from stu;
- 将表重新命名(a改成b)
四、sqlite3在c中使用和一些函数接口
- 导入头文件<sqlite3.h>
- 编译时加上-lsqlite3.h
gcc example.c -lsqlite3
1. sqlite3_open 数据库的连接和创建
原型:
int sqlite3_open(const char* filename,sqlite3 **ppDb);
filename:指定要打开的数据库的路径和名字。没有则会新建。
ppDb是二级指针,指向的一级指针最终会存储数据库加载到内存空间的首地址。一般会提前定义
sqlite3 *db;
再取其地址,即为二级指针。
返回值:
如果数据库连接成功打开,则返回SQLITE_OK(通常为0)。
失败则返回error_code。使用sqlite3_errmsg()函数可以打印sqlite3的函数的运行失败后的错误信息。
- 代码示例
#include<sqlite3.h>
#include<stdio.h>
int main()
{
sqlite3 *db;
if(sqlite3_open("./example.db",&db)!=SQLITE_OK)
{
fprintf(stderr,"Can't open database:%s\n",sqlite3_errmsg(db));
return -1;
}
else{
fprintf(stdout,"Opened database successfully\n");
}
return 0;
}
2. sqlite3_open 数据库的关闭
原型:int sqlite3_close(sqlit3 *db);
eg:
sqlit3_close(db);
3. sqlite3_errmsg 获取最近一次数据库错误信息
原型:const char * sqlite3_errmsg(sqlite3 \*db);
eg: sqlite3_errmsg(db);
4. sqlite3_errcode 获取与数据库连接相关的最近一次错误代码的函数。
fprintf(stderr, "Can't open database: %s (Error code: %d)\n", sqlite3_errmsg(db), errcode);
返回值为错误码
5. sqlite3_exec 执行SQL语句。
- 非常适合执行不需要返回结果集或只需要简单处理结果的 SQL 语句。
- 值得注意的是每当查询到一条记录满足条件时,callback函数就会被sqlite_exec调用一次。
int sqlite3_exec(
sqlite3 *db, /* 数据库连接对象 */
const char *sql, /* SQL 语句 */
int (*callback)(void*,int,char**,char**), /* 回调函数 */
void *arg, /* 第一个参数传递给回调函数 */
char **errmsg /* 错误信息字符串 */
);
db:一个指向已打开的 SQLite 数据库连接对象的指针。
sql:一个指向包含要执行的 SQL 语句的字符串的指针。可以包含多条以分号分隔的 SQL 语句。
int (*callback)(void*,int,char**,char**):一个回调函数,用于处理查询结果。如果不需要处理结果,可以传递 NULL。
void *arg:传递给回调函数的第一个参数。可以是任意类型的指针,在回调函数中使用。如果不需要,可以传递 NULL。
char **errmsg:一个指向错误信息字符串的指针。如果不需要错误信息,可以传递 NULL。如果发生错误,SQLite 将分配一个包含错误消息的字符串,并将其地址存储在 *errmsg 中。调用者需要使用 sqlite3_free 函数来释放这个字符串。
回调函数(只处理查询结果,其余时候填NULL)
int callback(void *arg, int column_count, char **column_values, char **column_names);
arg:传递给 sqlite3_exec 的第四个参数。
column_count:查询结果中的列数。
column_values:一个指向包含每一列值的字符串数组的指针。指向查询到的结果内容
column_names:一个指向包含每一列名称的字符串数组的指针。指向查询到的表头
返回值:
成功返回SQLITE_OK(通常为0)。
失败返回错误码。
- 代码示例
//回调函数为空
char sql[128] = "create table stu(id int,name char,score float);";
char *errmsg =NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
printf("Can't create stu:%s __%d__\n",errmsg,__LINE__);
return -1;
}
else
{
fprintf(stdout,"Create table stu success __%d__\n",__LINE__);
}
//回调函数不为空
#include<sqlite3.h>
#include<stdio.h>
int callback(void *arg, int column_count, char **column_values, char **column_names)
{//callback 函数接受一个 void* 类型的参数 arg,它实际上是 flag 的地址。
printf("column_count = %d __%d__\n",column_count,__LINE__);
return 0;
}
int main()
{
sqlite3 *db;
if(sqlite3_open("./example.db",&db)!=SQLITE_OK)
{
fprintf(stderr,"Can't open database:%s\n",sqlite3_errmsg(db));
return -1;
}
else{
fprintf(stdout,"Opened database successfully\n");
}
char* errmsg =NULL;
char sql1[512] = "create table if not exists stu(id int,name char,score float);\
insert into stu values(1,\"张三\",100);\
insert into stu values(2,\"李四\",100);";
if(sqlite3_exec(db,sql1,NULL,NULL,&errmsg)!=SQLITE_OK)
{
printf("Can't create stu:%s __%d__\n",errmsg,__LINE__);
return -1;
}
else
{
fprintf(stdout,"Create table stu success __%d__\n",__LINE__);
}
char sql[128] = "select * from stu where score=100;";
int flag =0;
if(sqlite3_exec(db,sql,callback,&flag,&errmsg)!=SQLITE_OK)
{
fprintf(stderr,"Sqlite3_exec:%s __%d__\n",errmsg,__LINE__);
sqlite3_free(errmsg);
return -1;
}
else
{
printf("Data query success!!!");
}
return 0;
}
6. sqlite_get_table 专门用于执行查询相关的sql语句
- 用于执行查询并将结果存储在一个二维数组中。它简化了查询结果的处理,不需要编写复杂的回调函数。
函数原型:
int sqlite3_get_table(
sqlite3 *db, // 数据库连接
const char *zSql, // SQL 查询语句
char ***pazResult, //指向结果数组的指针。该数组会包含查询结果,格式是一个二维数组。
int *pnRow, // 返回的行数
int *pnColumn, // 返回的列数
char **pzErrmsg // 错误信息
);
返回值是一个整数,表示操作的结果。如果成功,返回 SQLITE_OK。否则,返回相应的错误代码。
pazResult,将查询到的结果的表格存在此二维数组中,可以以访问二维数组的方式访问它的内容
换行符巧用
for(int i=0;i<(rows+1)*columns;i++)
{
printf("\n");//确保每一行如数据库一样。
}
- 一定要注意结果中有表头的情况,在遍历结果时row需要+1。
7. sqlite_free_table 释放动态内存数组
- 用于释放由 sqlite3_get_table 分配的内存。因为 sqlite3_get_table 动态分配了一个二维数组来存储查询结果,使用完毕后,需要调用 sqlite3_free_table 来释放这些内存,以防止内存泄漏。
sqlite3_free_table(results);
8.代码实例
#include <sqlite3.h>
#include <stdio.h>
// 回调函数,用于处理查询结果
int callback(void *arg, int column_count, char **column_values, char **column_names) {
for (int i = 0; i < column_count; i++) {
printf("%s = %s\n", column_names[i], column_values[i] ? column_values[i] : "NULL");
}
printf("\n");
return 0;
}
int main() {
sqlite3 *db;
char *errmsg = NULL;
char **results;
int rows, columns;
int rc;
// 打开数据库
rc = sqlite3_open("example.db", &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return -1;
} else {
fprintf(stdout, "Opened database successfully\n");
}
// 创建表并插入数据
const char *sql_create_insert =
"CREATE TABLE IF NOT EXISTS stu(id INT, name TEXT, score REAL);"
"INSERT INTO stu VALUES(1, '张三', 100.0);"
"INSERT INTO stu VALUES(2, '李四', 95.0);";
if (sqlite3_exec(db, sql_create_insert, NULL, NULL, &errmsg) != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return -1;
} else {
fprintf(stdout, "Table created and data inserted successfully\n");
}
// 使用回调函数查询数据
const char *sql_select = "SELECT * FROM stu WHERE score=100;";
int flag = 0;
if (sqlite3_exec(db, sql_select, callback, &flag, &errmsg) != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return -1;
} else {
fprintf(stdout, "Data query success\n");
}
// 使用 sqlite3_get_table 查询数据
const char *sql_get_table = "SELECT * FROM stu;";
if (sqlite3_get_table(db, sql_get_table, &results, &rows, &columns, &errmsg) != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return -1;
}
// 打印查询结果
printf("Number of rows: %d\n", rows);
printf("Number of columns: %d\n", columns);
for (int i = 0; i < (rows + 1) * columns; i++) {
if (i % columns == 0 && i != 0) {
printf("\n");
}
printf("%s\t", results[i]);
}
printf("\n");
// 释放查询结果数组
sqlite3_free_table(results);
// 关闭数据库
sqlite3_close(db);
return 0;
}