数据库
sqlite官网:https://www.sqlite.org/index.html
数据库的安装
离线安装:
sudo dpkg -i libsqlite3-dev_3.22.0-1ubuntu0.4_amd64.deb
sudo dpkg -i sqlite3_3.22.0-1ubuntu0.4_amd64.deb
在线安装:
sudo apt-get install sqlite3
sudo apt-get install libsqlite3-dev
如何检查是否安装成功
在终端输入 sqlite3 ,直接回车,如果能看到下面的sqlite3的命令行,就说明已经装好了
输入 .quit 回车 退出数据库
打开数据库文件
如果不打开数据库文件,直接通过sqlite3的终端操作,所有的操作都是在内存上操作,并没有把数据落到硬盘上,所以当数据库程序退出时,数据就没了。
打开数据库文件的方式1:
sqlite3 数据库文件名
注意:数据库文件名随便起,一般都以 .db 结尾
这种方式如果文件存在 则直接打开使用 如果不存在 则新建并打开使用
打开数据库文件的方式2:
先使用 sqlite3 进入到sqlite数据的程序的终端
然后 使用 .open 数据库文件名 方式打开
数据库的操作
系统命令
不同的数据库软件 一般系统命令都是不一样的,
sqlite3数据库的系统命令是以 . 开头的 结尾不能加分号
.help 获取帮助信息
.exit 退出数据库程序
.quit 退出数据库程序 .q 也可以
.tables 查看数据库文件中有哪些数据表
.schema 查看数据表的建表语句(表的结构)
.headers on|off 查询结果是否显示表头信息
关系型数据库表的结构
SQL语句
只要是关系型数据库,SQL语句都是通用的
SQL要求 不能以.开头 必须有分号结尾
常用的sql语句
//sql语句中 关键字不区分大小写 但是一般情况下 我们都把关键字大写
1.建表语句
打开新的数据库文件时,里面是没有数据表的,需要我们自己创建
CREATE TABLE 表名(字段名1 字段类型1, 字段名2 字段类型2, ...);
字段的类型:
整数:INT INTEGER
字符串:CHAR TEXT
例如:
CREATE TABLE student(id INT, name TEXT, score INTEGER);
2.向表中插入数据
//这种插入方式 必须给每个字段都赋值 从左到右依次赋值
//SQL语句中使用字符串时 需要用 单引号 或者 双引号引起来
INSERT INTO student VALUES(1001, "zhangsan", 98);
//这种方式可以指定只给几个字段赋值 根据给定的字段从左到右依次赋值
INSERT INTO student(id, name) VALUES(1002, 'lisi');
3.查询表中的记录
SELECT * FROM student; //查询表中所有记录的所有字段 * 所有字段
SELECT name FROM student; //只查询表中所有记录的 name 字段
SELECT name,score FROM student; //只查询表中所有记录的 name 和 score 字段
//查询表中score=98分的所有记录的所有字段
SELECT * FROM student WHERE score=98;
//条件如果是字符串 也得用 单引号 或者 双引号 引起来
SELECT * FROM student WHERE name="zhangsan";
//如果有多个条件 也可以使用 AND 或者 OR 连接 AND 表示并且 OR 表示或者
SELECT * FROM student WHERE score=98 AND name="zhangsan";
SELECT * FROM student WHERE score=98 OR name="lisi";
//对查询的结果进行排序
//ORDER BY 根据哪个字段排序
//ASC 升序 DESC 降序 默认不写是升序
SELECT * FROM student ORDER BY score DESC;//将查询结果根据成绩降序排序
4.更新表中的记录
//将id为1001的记录中 name字段改成 "xiaoming"
UPDATE student SET name="xiaoming" WHERE id=1001;
//如果要修改多个字段的值 可以用逗号分隔
UPDATE student SET name="xiaohong",score=80 WHERE id=1005;
//注意:即使没有符合条件的记录 也不报错 只不过没有任何事情发生
5.删除表中的记录
//删除表中 id=1001 的记录
DELETE FROM student WHERE id=1001;
//和更新同理 即使条件不成立 也不会报错 只是没有事情发生
6.删除数据表
DROP TABLE 表名;
//关于列的操作 了解即可 因为表的结构在设计阶段一般就都定好了,不会更改
7.在表中添加一个字段
//在表student中添加一个新的字段 sex 类型为 CHAR
ALTER TABLE student ADD COLUMN sex CHAR;
8.删除一个字段
sqlite3 不允许直接删除字段的 可以中转达到目的
1> 先创建一张新的表
CREATE TABLE temp AS SELECT id,name FROM student;
2> 删除原来的旧表
DROP TABLE student;
3> 将新表重命名为旧表的名字
ALTER TABLE temp RENAME TO student;
9.主键 ----重要
//PRIMARY KEY 在建表的时候可以使用该关键字指定某个字段为主键
//插入数据时,主键不允许冲突的 ----插入冲突的数据 会报错 主键冲突
CREATE TABLE student(id INT PRIMARY KEY, name CHAR, score INT);
sqlite3常用的API接口
查看函数的说明 在 sqlite的官网查看
编码时需要加头文件 #include <sqlite3.h>
编译时需要链接库文件 -lsqlite3
例子都在下面使用数据库实现学生管理系统的例子中。
1.打开数据库文件的函数
int sqlite3_open(const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */ );
功能:
打开一个数据库
参数:
filename 数据库名字(不写路径默认的就是当前路径下寻找)
存在直接打开 不存在则新建并打开
ppDb 操作数据库的指针,句柄。
返回值:
成功 SQLITE_OK
失败 错误码
2.关闭数据库的函数
int sqlite3_close(sqlite3* db);
参数:数据的句柄
3.获取错误信息的函数
const char *sqlite3_errmsg(sqlite3* db);
功能:获取错误信息的描述(最后一次的出错信息)
参数:数据的句柄
返回值:指向错误信息字符串的指针
4.执行SQL语句的函数
int sqlite3_exec(sqlite3* db, const char *sql,
int (*callback)(void*,int,char**,char**),
void *arg, char **errmsg);
功能:
执行一条sql语句
参数:
db 数据库的句柄指针
sql 将要被执行sql语句
callback 回调函数, 只有在查询语句时,才使用
arg 为callback 传参的, 只有在查询语句时,才使用
errmsg 错误信息的地址
如果使用了最后一个参数 还得手动释放错误信息占用的空间
返回值:
成功 SQLITE_OK
出错 错误码
------------------------关于 sqlite3_exec的回调函数------------------
int (*callback)(void* arg, int ncolumn, char** f_value, char** f_name)
功能:
得到查询结果
参数:
arg 为回调函数传递参数使用的
ncolumn 记录中包含的字段的数目
f_value 包含每个字段值的指针数组
f_name 包含每个字段名称的指针数组
返回值:
成功 SQLITE_OK
出错 非0
5.释放错误信息的空间
void sqlite3_free(void *p);
6.查询数据库的函数
int sqlite3_get_table(sqlite3 *db, const char *zSql, char ***pazResult,
int *pnRow, int *pnColumn, char **pzErrmsg);
功能:
查询数据库,它会创建一个新的内存区域来存放查询的结果信息
参数:
db 数据库操作句柄
sql 数据库的sql语句
pazResult 查询的结果
nRow 行数 不包括字段名的行数
nColumn 列数
errmsg 错误消息 如果使用了 也得使用 sqlite3_free 来释放空间
返回值:
成功 SQLITE_OK
出错 错误码
7.释放由sqlite3_get_table产生的结果集
void sqlite3_free_table(char **result);
使用数据库实现学生管理系统
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <unistd.h>
#define DATABASE "hqyj.db"
//打印菜单的函数
void print_menu(){
printf("----------------------------------------\n");
printf("| 1.添加 2.修改 3.查找 4.删除 5.退出 |\n");
printf("----------------------------------------\n");
printf("input your choose : ");
}
//程序初始化的函数
sqlite3 *process_init(){
sqlite3 *my_db = NULL;
char *errstr = NULL;
int ret = 0;
//打开数据库文件
if(SQLITE_OK != (ret = sqlite3_open(DATABASE, &my_db))){
printf("打开数据库文件失败 :errcode[%d], errstr[%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("打开数据库文件成功..\n");
//尝试建立数据表
//组建sql语句 代码中组装的sql语句 无需在结尾加 ;
// IF NOT EXISTS 表示如果表存在则直接使用 不存在在执行创建的语句
char sqlbuff[256] = "CREATE TABLE IF NOT EXISTS student(id INT PRIMARY KEY, name TEXT, score INT)";
//执行sql语句
if(SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, &errstr))){
printf("建表失败 errcode[%d], errstr[%s]\n", ret, errstr);
exit(-1);
}
printf("尝试建表成功..\n");
//如果用了 sqlite3_exec 的第五个参数 记得释放空间
sqlite3_free(errstr);
return my_db;
}
//添加学员信息的函数
void insert_student(sqlite3 *my_db){
int input_id = 0;
char input_name[32] = {0};
int input_score = 0;
printf("请输入新学员的信息(id INT, name TEXT, score INT) : ");
scanf("%d%s%d", &input_id, input_name, &input_score);
//组装sql语句
char sqlbuff[256] = {0};
sprintf(sqlbuff, "INSERT INTO student VALUES(%d, '%s', %d)", \
input_id, input_name, input_score);
//注意 数据库代码出现错误 第一件事儿 先把要执行的sql语句打印出来 !!!
//printf("yangfs sqlbuff:[%s]\n", sqlbuff);
//执行sql语句
int ret = 0;
if(SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL))){
printf("学员信息插入失败: errcode[%d], errstr[%s]\n", ret, sqlite3_errmsg(my_db));
return;
}
printf("学员信息插入成功..\n");
return;
}
//修改学员信息的函数 根据学员的id 修改 name 和 score
void modify_student(sqlite3 *my_db){
int input_id = 0;
printf("请输入要修改的学员的id(INT):");
scanf("%d", &input_id);
char input_name[32] = {0};
int input_score = 0;
printf("请输入新的信息(name TEXT, score INT) : ");
scanf("%s%d", input_name, &input_score);
//组装sql语句
char sqlbuff[256] = {0};
sprintf(sqlbuff, "UPDATE student SET name='%s',score=%d WHERE id=%d", \
input_name, input_score, input_id);
//执行sql语句
int ret = 0;
if(SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL))){
printf("学员信息修改失败: errcode[%d], errstr[%s]\n", ret, sqlite3_errmsg(my_db));
return;
}
printf("学员信息修改成功..\n");
return;
}
int flag = 0; //打印表头的标志位 0 需要打印 1 不需要打印
//sqlite3_exec的回调函数 每查询到一条记录 callback就会被调用一次
int callback(void* arg, int ncolumn, char** f_value, char** f_name){
//打印表头
int i = 0;
if(0 == flag){
for(i = 0; i < ncolumn; i++){
printf("%20s", f_name[i]);
}
printf("\n");
flag = 1;
}
//再打印记录的值
for(i = 0; i < ncolumn; i++){
printf("%20s", f_value[i]);
}
printf("\n");
return 0;//必须要写return 否则报错 query aborted
}
//查找学员信息的函数 使用callback回调函数实现
void search_student_1(sqlite3 *my_db){
printf("\n");
//组装sql语句
char sqlbuff[256] = "SELECT * FROM student";
//执行sql语句
int ret = 0;
flag = 0;//重置打印表头的标志位
if(SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, callback, NULL, NULL))){
printf("学员查询删除失败: errcode[%d], errstr[%s]\n", ret, sqlite3_errmsg(my_db));
return;
}
printf("学员信息查询成功..\n");
printf("\n");
return;
}
//查找学员信息的函数 使用sqlite3_get_table回调函数实现
void search_student_2(sqlite3 *my_db){
printf("\n");
//组装sql语句
char sqlbuff[256] = "SELECT * FROM student";
//执行sql语句
int ret = 0;
char **presult = NULL;
int row = 0;
int column = 0;
if(SQLITE_OK != (ret = sqlite3_get_table(my_db, sqlbuff, &presult, &row, &column, NULL))){
printf("学员查询删除失败: errcode[%d], errstr[%s]\n", ret, sqlite3_errmsg(my_db));
return;
}
//处理查询到的结果
//先打印表头
int i = 0;
int j = 0;
for(i = 0; i < column; i++){
printf("%20s", presult[i]);
}
printf("\n");
int index = i;
//再打印字段的值
for(i = 0; i < row; i++){
for(j = 0; j < column; j++){
printf("%20s", presult[index++]);
}
printf("\n");
}
//释放有sqlite3_get_table产生的结果集
sqlite3_free_table(presult);
printf("学员信息查询成功..\n");
printf("\n");
return;
}
//删除学员信息的函数 根据学员的id 删除学员的信息
void delete_student(sqlite3 *my_db){
int input_id = 0;
printf("请输入要删除的学员的id(INT):");
scanf("%d", &input_id);
//组装sql语句
char sqlbuff[256] = {0};
sprintf(sqlbuff, "DELETE FROM student WHERE id=%d", input_id);
//执行sql语句
int ret = 0;
if(SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL))){
printf("学员信息删除失败: errcode[%d], errstr[%s]\n", ret, sqlite3_errmsg(my_db));
return;
}
printf("学员信息删除成功..\n");
return;
}
int main(int argc, const char *argv[])
{
printf("欢迎使用 HQYJ 学生管理系统..\n");
printf("程序初始化中..\n");
sqlite3 *my_db = process_init();
int choose = 0;
while(1){
print_menu();
scanf("%d", &choose);
switch(choose){
case 1:
insert_student(my_db);
break;
case 2:
modify_student(my_db);
break;
case 3:
//search_student_1(my_db);
search_student_2(my_db);
break;
case 4:
delete_student(my_db);
break;
}
if(5 == choose){
break;
}
}
//关闭数据库文件
sqlite3_close(my_db);
printf("欢迎下次使用本系统..\n");
return 0;
}
关于callback回调函数的结果集
以表中记录如下图所示的情况为例, 执行 “SELECT * FROM student”
关于sqlite3_get_table函数产生的结果集
以表中记录如下图所示的情况为例, 执行 “SELECT * FROM student”