数据库:存储文件(数据集合) + 数据库管理系统DBMS(软件)
之前的学生管理系统 关闭终端后 数据就不存在了。因为那时的数据存到了内存上。等进程结束之后,内存就被回收了。
数据库会对数据做加密或者压缩,等需要读的时候会解密。不会占用太多的硬盘空间。
分布式系统-(集群式服务)
常用数据库
大型数据库:Oracle公司
中型数据库:Server、mySql
小型数据库:
基于linux嵌入式的数据库:SQlite、
数据库的安装
sqlite数据库官网:https://www.sqlite.org
离线安装
sudo dpkg -i sqlite3_3.22.0-1ubuntu0.4_amd64.deb 数据库软件
sudo dpkg -i libsqlite3-dev_3.22.0-1ubuntu0.4_amd64.deb 数据库的库文件
在线安装
sudo apt-get install sqlite3 libsqlite3-dev
如何检查是否已经安装成功:
在终端输入 sqlite3 如果能进入到下面的界面 说明已经装好了
退出 sqlite3 的终端 输入 .quit 回车
打开数据库文件
注意:如果直接使用sqlite3命令 进入到sqlite的终端操作,那么所有的操作都是在内存上操作的。
当数据库程序退出的时候,所有的数据就都没有了,不会落到硬盘上。 所以,我们操作数据库时,要先打开数据库文件,再操作。
打开数据库文件的方式1:
sqlite3 数据库文件名 数据库文件名可以随便起,但是一般都是以.db 结尾的
打开数据库文件的方式2:
先使用 sqlite3 进入到sqlite3的终端,
然后使用 .open 数据库文件名 来打开数据库文件
数据的操作
系统命令
不同的数据库,系统命令一般是不一样的,
sqlite3 数据库的系统命令都是以 . 开头的 结尾不能加 分号
.help 打开帮助手册
.open 打开数据库文件
.exit 退出数据库程序
.quit 退出数据库程序 使用 .q 也可以
.tables 查看数据库中有哪些数据表
.schema 查看表结构(建表语句)
.headers on|off 查询结果是否显示字段名(表头) on 显示 off 不显示
SQL语句(重要)
只要是关系型数据库 SQL 语句都是通用的
SQL的特点 不能以.开头 结尾必须有 分号
常用的sql语句:
//sql语句中关键字是不区分大小写的,一般我们写的时候都写成大写
1.建表语句
//注意:新创建的数据库文件中是没有数据表的 需要我们自己创建
CREATE TABLE 表名(字段名1 字段的类型1, 字段名2, 字段类型2);
字段类型:
整型:INT INTEGER
字符串:CHAR TEXT
不支持浮点型 字符串可表示"3.14"
例如:
CREATE TABLE student(id INT, name CHAR, score INTEGER);
2.插入语句
INSERT INTO student VALUES(1001, "张三", 98);
//sql语句中的字符串需要用 单引号 '' 或者双引号 "" 引起来
//注意:上面的插入语句 要求 必须从左到右给每个字段都赋值
//如果只想给部分字段赋值,可以使用下面的用法
INSERT INTO student(id, score) VALUES(1002, 96);//指定字段的赋值
INSERT INTO student(id, name) VALUES(1003, '王五');
3.查询语句
SELECT * FROM student; //查询所有记录的所有字段 * 表示所有字段
SELECT id,score FROM student; //查询所有记录的id和score字段
SELECT * FROM student WHERE score=70; //查询所有score是70的记录的所有字段
//WHERE 后面的条件可以使用 AND OR 连接多句
//AND 并且 OR 或者
SELECT * FROM student WHERE score=70 AND name='小明';
SELECT * FROM student WHERE score=70 OR id=1005;
//查询所有满足score=70并且name="小明"条件的记录的 id字段
SELECT id FROM student WHERE score=70 AND name='小明';
//对查询结果可以排序
// ORDER BY 根据那个字段排序
// ASC 升序 DESC 降序 不写 默认是 升序
// 查询表中所有记录的所有字段,并将结果根据成绩升序排序
SELECT * FROM student ORDER BY score ASC;
// 查询表中所有记录的所有id=1005的字段,并将结果根据成绩降序排序
SELECT * FROM student WHERE id=1005 ORDER BY score DESC;
4.更新记录
//将表中所有id=1002的记录的name字段更新成 "李四"
UPDATE student SET name="李四" WHERE id=1002;
//将表中所有id=1005的记录的name字段更新成 "学霸"且score更新成100
UPDATE student SET name="学霸",score=100 WHERE id=1005;
//注意:即使没有满足条件的记录,那么该sql语句也不报错
//只不过没有现象发生,任何记录都不会被更新
5.删除记录
//删除表中所有name="王五的记录"
DELETE FROM student WHERE name='王五';
//删除表中所有score=100或者id=1001的记录
DELETE FROM student WHERE score=100 OR id=1001;
//注意:即使没有满足条件的记录,那么该sql语句也不报错
//只不过没有现象发生,任何记录都不会被删除
6.删除表
DROP TABLE 表名;
//对列的操作了解即可,因为实际开发中表的结构在设计阶段一般都定好了
//不会随便更改,所以对列的操作基本不使用----了解即可
7.给表添加一列
//给student表中添加一个 sex字段 类型为 TEXT
ALTER TABLE student ADD COLUMN sex TEXT;
8.删除表中的一列
sqlite3 不允许直接删除一列
1)先创建一张新表
CREATE TABLE temp AS SELECT id,name,score FROM student;
2)删除原来的旧表
DROP TABLE student;
3)对新表重命名
ALTER TABLE temp RENAME TO student;
9.主键(PRIMARY KEY)
在建表的时候可以使用PRIMARY KEY关键字来指定某一个字段为主键
后面在执行插入语句的时候,主键字段不允许冲突
如果插入冲突的记录会报错:主键冲突
例如:
CREATE TABLE student(id INT PRIMARY KEY, name TEXT, score INT);
//表示id字段为主键 插入时 id不允许冲突
扩展:
程序中要有操作数据库的能力,所以要讲API,就可以让程序调函数操作数据库。
这些函数是数据库提供给我们的,不是操作系统提供的。
所以要找这些接口函数的函数说明书–官网
sqlite3数据库常用的API接口
使用sqlite3提供的函数,编码时需要加头文件 #include <sqlite3.h>
编译时,需要连接sqlite3的库 -lsqlite3
所有API的例子都在下面使用sqlite3数据库实现学生管理系统的例子中
1.打开数据库文件的函数
int sqlite3_open(const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */ );
功能:
打开一个数据库文件
参数:
filename 数据库文件的名字
ppDb 操作数据库的指针,句柄。
返回值:
成功 SQLITE_OK
失败 错误码
注意:sqlite3应该是结构体,自己定义一个 sqlite3 *my_db = NULL;
2.获取错误信息的函数
const char *sqlite3_errmsg(sqlite3* db);
功能:获取最后一次错误信息描述
3.关闭数据库文件的函数
int sqlite3_close(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 错误信息的地址
如果使用了 需要记得使用 sqlite3_free 释放空间
返回值:
成功 SQLITE_OK
失败 错误码
-----------------------关于sqlite3_exec函数的回调函数------------------
int (*callback)(void* arg, int ncolumn, char **f_value, char **f_name)
功能:
得到查询结果
参数:
arg 为回调函数传递参数使用的
ncolumn 记录中包含的字段的数目
f_value 包含每个字段值的指针数组
f_name 包含每个字段名称的指针数组
返回值:
成功 0
出错 非0
5.获取查询结果的函数
int sqlite3_get_table(sqlite3 *db, const char *zSql, char ***pazResult,
int *pnRow, int *pnColumn, char **pzErrmsg);
功能:
查询数据库,它会创建一个新的内存区域来存放查询的结果信息
在应用程序处理完结果后 需要调用sqlite3_free_table 释放结果集 否则内存泄漏
参数:
db 数据库操作句柄
zSql 查询数据库的sql语句
azResult 查询的结果
nRow 不包含字段名的行数
nColumn 列数
errmsg 错误消息 如果使用了记得用 sqlite3_free 释放空间
返回值:
成功 SQLITE_OK
失败 错误码
6.释放sqlite3_get_table函数产生的结果集的函数
void sqlite3_free_table(char **result);
使用sqlite3数据库实现学生管理系统
注意!!!
比如,你在某个路径下打开了sqlite3 zx.db ,系统则会在这个路径下创建 zx.db 的数据库文件。
学生管理系统完成以下功能: 1.添加 2.修改 3.删除 4.查询 5.退出
查询
程序 去执行查询语句不一定是为了打印到终端。(例:像 输入账号和密码 是为了查询到账号然后登录)
说明 程序去执行查询语句的话,一定要有一块空间去存储查询的结果。具体要对结果如何操作是程序员的事情。想运算就运算,想打印就打印。
查询的两种方式:
1-使用回调函数实现
执行sql语句的函数
int sqlite3_exec(sqlite3* db, const char *sql,
int (*callback)(void*,int,char**,char**),
void *arg, char **errmsg);
思考怎样可以在函数内部把数据给到调用者。(返回值是要返回成功或者失败的,所以不能利用返回值)
所以 要求自己封装一个函数 int (*callback)(void*,int,char**,char**)。
-----------------------关于sqlite3_exec函数的回调函数------------------
int (*callback)(void* arg, int ncolumn, char **f_value, char **f_name)
功能:
得到查询结果
参数:
arg 为回调函数传递参数使用的
ncolumn 记录中包含的字段的数目
f_value 包含每个字段值的指针数组
f_name 包含每个字段名称的指针数组
返回值:成功 0
出错 非0
自己封装的函数 : int callback(void *arg,int n,char **a,char **b)
int n: select 中有几个字段 就把字段数(列数)通过第二个参数传回来(与表有关 与select后边的字段数量有关,例select id,name,score from student;这种情况n=3)
char *类型的指针数组,
"id" "name" "score"
s1 char* |char* |char* s2 char* |char* |char*
"1001" "zhangsan" "98"
s1传给形参a,s2传给形参b.
此时,通过a可以访问记录(数组成员),通过b可以访问所有的字段名。
注意:自己封装的函数callback()在exec内部并不只是被调用了一次,查询的结果有几条记录就被调用几次。
s1字段值 s2字段名
int callback(void *arg,int n,char **a,char **b)
第一次调用 就传这些数据
第二次调用 s1的指向就变了,s2不变---->就又能获取第二条信息了
...... ........ ....... .......
f_value[0] --->"1002"
char *p = "1002";
如果想取出"1002"的话,不能取 *f_value[0] ;
这样取出来的只有1 ,要用atoi()才能把"1002"取出来。
2-使用 sqlite3_get_table函数实现
获取查询结果的函数
int sqlite3_get_table(sqlite3 *db, const char *zSql, char ***pazResult,
int *pnRow, int *pnColumn, char **pzErrmsg);
功能:
查询数据库,它会创建一个新的内存区域来存放查询的结果信息
在应用程序处理完结果后 需要调用sqlite3_free_table 释放结果集 否则内存泄漏
参数:
db 数据库操作句柄
zSql 查询数据库的sql语句
pazResult 查询的结果
nRow 不包含字段名(表头)的行数
nColumn 列数
pzErrmsg 错误消息(类似 errmsg) 如果使用了记得用 sqlite3_free 释放空间
返回值:
成功 SQLITE_OK
失败 错误码
------------------------------------------------------------------------
例:
id name score
1001 张三 98
1002 李四 100
pazResult 查询的结果 会把查到的所有的结果(包括表头)(如例子一共9项)用malloc在内部生成一块空间),这块空间里生成的都是char* 类型的指针数组。(如例子一共9个成员)
0 1 2 3 4 5 6 7 8
char* char* char* char* char* char* char* char* char*
id name score 1001 张三 98 1002 李四 100
这个数组是在函数内部通过malloc的方式产生的。
因为要让我们能访问到这个数组,这个数组的操作空间的大小是 char* 的大小,所以我们要定义一个char**类型的指针p,char **p;所以我们要把p的地址传给pazResult
我们仅仅知道这个首地址是没用的,这样不知道字段名是多少。也不知道有多少条记录。
所以我们要知道列数nColumn,和行数nRow。
学生管理系统代码
总代码:
#include <head.h>
#include <sqlite3.h>
//select查询的方式有写两种 callback()回调函数 和 sqlite3_get_table()函数
//modify_student()函数使用的第一种方式(比较id)判断是否有某学生存在
//delete_student()函数使用的第二种方式(判断回调函数是否被执行)判断是否有某学生存在
void insert_student(sqlite3 *my_db);
void modify_student(sqlite3 *my_db);
void delete_student(sqlite3 *my_db);
void select_student_1(sqlite3 *my_db);
void select_student_2(sqlite3 *my_db);
void exit_student(sqlite3 *my_db );
int callback(void *arg, int ncolumn, char **f_value, char **f_name);
// 打印菜单的函数
void print_menu()
{
printf("----------------------------------------\n");
printf("| 1.添加 2.修改 3.删除 4.查询 5.退出 |\n");
printf("----------------------------------------\n");
}
// 进程初始化函数
sqlite3 *proc_init()
{
// 打开数据库文件
sqlite3 *my_db = NULL;
int ret = 0;
if (SQLITE_OK != sqlite3_open("hqyj.db", &my_db))
{
printf("sqlite3_open error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("数据库文件打开成功!!\n");
// 创建表
char sqlbuff[256] = "CREATE TABLE IF NOT EXISTS student(id int primary key,name char,score int)";
if (SQLITE_OK != sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("建表成功!!\n");
return my_db;
}
int main(int argc, const char *argv[])
{
sqlite3 *my_db = proc_init();
while (1)
{
print_menu();
int choose = 0;
printf("请输入你的选择:");
scanf("%d", &choose);
if(5 == choose){
break;
}
switch (choose){
case 1:
insert_student(my_db);
break;
case 2:
modify_student(my_db);
break;
case 3:
delete_student(my_db);
break;
case 4:
//select_student_1(my_db);
select_student_2(my_db);
break;
// case 5:
// exit_student(my_db);
default :
printf("没有此操作,请重新选择");
break;
}
}
printf("欢迎再次使用学生管理系统!!\n");
sqlite3_close(my_db);
return 0;
}
void exit_student(sqlite3 *my_db){
exit(-1);
}
int flag = 0; //定义一个全局变量,当做打印表头的标志位
//0 表示需要打印 1 表示不需要打印
//回调函数
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("%10s", f_name[i]);
}
printf("\n");
flag = 1;
}
// 在打印记录的值
for (i = 0; i < ncolumn; i++)
{
printf("%10s", f_value[i]);
}
printf("\n");
return 0 ; //必须要写 否则报错
}
// 查询有两种方式 1-使用回调函数查询--查询所有学员信息
void select_student_1(sqlite3 *my_db)
{
printf("\n");
// 组装sql语句
char sqlbuff[256] = {"SELECT * FROM student"};
//printf("sqlbuff:[%s]\n", sqlbuff);
int ret = 0;
int flag=0; // 全局变量,为了打印表头
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, callback, NULL, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("\n");
printf("hello\n");
return;
}
// 查询有两种方式 2-使用sqlite3_get_table()函数实现---查询所有学员信息
void select_student_2(sqlite3 *my_db)
{
printf("\n");
// 组装sql语句
char sqlbuff[256] = {"SELECT * FROM student"};
//printf("sqlbuff:[%s]\n", sqlbuff);
int ret = 0;
int i=0;
int j=0;
char **result=NULL;
int row = 0;
int column = 0;
if (SQLITE_OK != (ret = sqlite3_get_table(my_db, sqlbuff, &result, &row,&column, NULL)))
{
printf("sqlite3_get_table error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
//处理结果
//先打印表头
for (i = 0; i < column; i++){
printf("%10s", result[i]);
}
printf("\n");
int index=i;
//再打印记录的值
for(i=0;i<row;i++){
for(j=0;j<column;j++){
printf("%10s", result[index++]);
}
printf("\n");
}
//释放结果集 防止内存泄露
sqlite3_free_table(result);
printf("\n");
return;
}
void insert_student(sqlite3 *my_db)
{
int input_id;
char input_name[32];
int input_score;
int ret = 0;
printf("请输入你要添加的学员信息 [id][name][score]:");
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);
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("学员信息插入成功!\n");
return;
}
//判断是否有学院信息的方式1:通过传参比较id来确定
//要有一个回调函数(回调函数必须有返回值,否则调用第二次的时候就会报错)
int exist_student = 0; //定义全局变量
int find_student_1(void *arg, int ncolumn, char **f_value, char **f_name)
{
//比较传过来的input_id和f_value[0]中的数值
//如果相同则说明该学生存在
if(*(int*)arg == atoi(f_value[0])){
//则说明该学生存在--存在标志位置1
exist_student = 1;
}
return 0;
}
void modify_student(sqlite3 *my_db)
{
int input_id = 0;
char input_name[32] = {0};
int input_score = 0;
int ret = 0;
printf("请输入你要修改的学员id:");
scanf("%d", &input_id);
//判断是否有学员信息的方式1:通过传参比较id来确定
char select_sql[256]="select * from student";
exist_student = 0;//重置标志位
//执行select_sql查询语句
if (SQLITE_OK != (ret = sqlite3_exec(my_db, select_sql, find_student_1, &input_id, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
//通过判断标志位来判断 该学生是否存在
if(0 == exist_student){
//不存在
printf("查无此人...\n");
return;
}
//逻辑上这里应该 恢复标志位 ,但是我们的代码中使用查询语句之前,每次都会重置标志位
//所以这里省略了恢复标志位
printf("请输入你要修改的学员名字和分数 [name][score]:");
scanf("%s %d", input_name, &input_score);
// 组装sql语句
char sqlbuff[256] = {0};
ret = 0;
sprintf(sqlbuff, "UPDATE student SET name='%s' , score=%d where id=%d ", input_name, input_score, input_id);
printf("sqlbuff:[%s]\n", sqlbuff);
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("学员信息修改成功!\n");
return;
}
int find_student_2(void *arg, int ncolumn, char **f_value, char **f_name)
{
//只要执行了回调函数就说明学生被找到了
//修改标志位即可
exist_student = 1;
return 0;
}
void delete_student(sqlite3 *my_db)
{
int input_id = 0;
int ret = 0;
printf("请输入你要删除的学员id:");
scanf("%d", &input_id);
//判断是否有学员信息的方式2:通过判断回调函数执行的次数来确定
//这种方式的查询语句需要有条件where
//原理是:只有在id被找到的情况下才会进入回调函数<=>学生id只有被找到了才能执行回调函数
char select_sql[256]={0};
exist_student = 0;//重置标志位
sprintf(select_sql,"select * from student where id= %d ",input_id);
//执行select_sql查询语句
if (SQLITE_OK != (ret = sqlite3_exec(my_db, select_sql, find_student_2, &input_id, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
//通过判断标志位来判断 该学生是否存在
if(0 == exist_student){
printf("查无此人...\n");
return;
}
// 组装sql语句
char sqlbuff[256] = {0};
ret=0;
sprintf(sqlbuff, "DELETE FROM student WHERE id = %d;", input_id);
//printf("sqlbuff:[%s]\n", sqlbuff);
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("学员信息删除成功!\n");
return;
}
判断是否有学员信息的两种方式
判断是否有学员信息的方式1:通过传参比较 id 来确定
通过sqlite3_exe()函数的第四个参数arg,传参到callback回调函数中。
本例子通过modify_student()函数来实现的
//判断是否有学院信息的方式1:通过传参比较id来确定
//要有一个回调函数(回调函数必须有返回值,否则调用第二次的时候就会报错)
int exist_student = 0; //定义全局变量
int find_student_1(void *arg, int ncolumn, char **f_value, char **f_name)
{
//比较传过来的input_id和f_value[0]中的数值
//如果相同则说明该学生存在
if(*(int*)arg == atoi(f_value[0])){
//则说明该学生存在--存在标志位置1
exist_student = 1;
}
return 0;
}
void modify_student(sqlite3 *my_db)
{
int input_id = 0;
char input_name[32] = {0};
int input_score = 0;
int ret = 0;
printf("请输入你要修改的学员id:");
scanf("%d", &input_id);
//判断是否有学员信息的方式1:通过传参比较id来确定
char select_sql[256]="select * from student";
exist_student = 0;//重置标志位
//执行select_sql查询语句
if (SQLITE_OK != (ret = sqlite3_exec(my_db, select_sql, find_student_1, &input_id, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
//通过判断标志位来判断 该学生是否存在
if(0 == exist_student){
//不存在
printf("查无此人...\n");
return;
}
//逻辑上这里应该 恢复标志位 ,但是我们的代码中使用查询语句之前,每次都会重置标志位
//所以这里省略了恢复标志位
printf("请输入你要修改的学员名字和分数 [name][score]:");
scanf("%s %d", input_name, &input_score);
// 组装sql语句
char sqlbuff[256] = {0};
ret = 0;
sprintf(sqlbuff, "UPDATE student SET name='%s' , score=%d where id=%d ", input_name, input_score, input_id);
printf("sqlbuff:[%s]\n", sqlbuff);
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("学员信息修改成功!\n");
return;
}
判断是否有学员信息的方式2:通过判断 回调函数是否执行 来确定
这种方式的查询语句需要有条件where
原理是:只有在id被找到的情况下才会进入回调函数<=>学生id只有被找到了才能执行回调函数
本例子通过delete_student()函数来实现的
int find_student_2(void *arg, int ncolumn, char **f_value, char **f_name)
{
//只要执行了回调函数就说明学生被找到了
//修改标志位即可
exist_student = 1;
return 0;
}
void delete_student(sqlite3 *my_db)
{
int input_id = 0;
int ret = 0;
printf("请输入你要删除的学员id:");
scanf("%d", &input_id);
//判断是否有学员信息的方式2:通过判断回调函数执行的次数来确定
//这种方式的查询语句需要有条件where
//原理是:只有在id被找到的情况下才会进入回调函数<=>学生id只有被找到了才能执行回调函数
char select_sql[256]={0};
exist_student = 0;//重置标志位
sprintf(select_sql,"select * from student where id= %d ",input_id);
//执行select_sql查询语句
if (SQLITE_OK != (ret = sqlite3_exec(my_db, select_sql, find_student_2, &input_id, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
//通过判断标志位来判断 该学生是否存在
if(0 == exist_student){
printf("查无此人...\n");
return;
}
// 组装sql语句
char sqlbuff[256] = {0};
ret=0;
sprintf(sqlbuff, "DELETE FROM student WHERE id = %d;", input_id);
//printf("sqlbuff:[%s]\n", sqlbuff);
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL)))
{
printf("sqlite3_exec error : errno = [%d] errstr = [%s]\n", ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("学员信息删除成功!\n");
return;
}