目录
基于SQLite数据库的学生管理系统
SQLite数据库用法 : SQLite
错误信息获取
全文使用
sqlite3_exec(sql_db, buff, NULL, NULL, NULL)
→printf("errmsg[%s]\n",sqlite3_errmsg(sql_db))
代码实现
student_system.c
#include "./my_sqlite3.h"
//打印功能菜单
void print_menu()
{
printf("--------------------------------------------------\n");
printf("| 1.添加 2.删除 3.修改 4.查询所有学员 5.退出|\n");
printf("--------------------------------------------------\n");
printf("输入您的选择 : ");
}
int main(int argc, const char *argv[])
{
// 句柄---数据库初始化
sqlite3 *sql_db = proc_init();
int choose = 0; // 选择
while (1)
{
print_menu(); // 打印功能菜单
scanf("%d", &choose); // 输入选择
switch (choose)
{
case 1:
insert_student(sql_db); // 添加
break;
case 2:
delete_student(sql_db); // 删除
break;
case 3:
update_student(sql_db); // 修改
break;
case 4:
// search_student1(sql_db); // 查询所有学员---方法 1 :sqlite3_get_table
search_student2(sql_db); // 查询所有学员---方法 2 :callback 回调函数
break;
case 5:
break;
default:
printf("输入错误,只支持输入[1~5]\n");
break;
}
if (5 == choose)
{
break;
}
}
//关闭sqlite3 句柄
sqlite3_close(sql_db);
return 0;
}
// 1. 数据库初始化 ---打开数据文件、建表
sqlite3 *proc_init(void)
{
sqlite3 *sql_db = NULL;
//打开一个数据库文件,存在直接打开 不存在 新建并打开
int ret = sqlite3_open("NO1.db", &sql_db);
if (ret != SQLITE_OK)
{
perror("打开数据库文件 失败");
printf("返回值[%d] 错误信息[%s]\n", ret, sqlite3_errmsg(sql_db));
exit(-1);
}
//建表
/*
IF NOT EXISTS 表不存在则创建 ;表存在则直接使用,而不会报错
引号里面sql语句后面不用加分号
*/
char sql_buff[256] = "CREATE TABLE IF NOT EXISTS student(id INT PRIMARY KEY, name CHAR, score INT)";
//执行sql语句
ret = sqlite3_exec(sql_db, sql_buff, NULL, NULL, NULL);
if (ret != SQLITE_OK)
{
perror("建表 失败");
printf("返回值[%d] 错误信息[%s]\n", ret, sqlite3_errmsg(sql_db));
exit(-1);
}
return sql_db;
}
// 1. 添加
void insert_student(sqlite3 *sql_db)
{
int id, score, ret;
char name[32];
printf("输入 ID 姓名 成绩 : ");
scanf("%d %s %d", &id, name, &score);
char sql_buff[256] = {0};
//填写sql语句
/*
在代码中组装的sql语句本身就是一个字符串 如果某个字段的值是字符串类型
就需要用 单引号 '' 引起来 引号里面sql语句后面不用加分号
*/
sprintf(sql_buff, "INSERT INTO student VALUES(%d,'%s',%d)", id, name, score);
//执行sql语句
ret = sqlite3_exec(sql_db, sql_buff, NULL, NULL, NULL);
if (ret != SQLITE_OK)
{
perror("添加 失败");
printf("返回值[%d] 错误信息[%s]\n", ret, sqlite3_errmsg(sql_db));
exit(-1);
}
printf("学员信息添加成功\n");
return;
}
// 2. 删除
void delete_student(sqlite3 *sql_db)
{
int id, ret;
printf("输入需要删除 ID : ");
scanf("%d", &id);
char sql_buff[256] = {0};
//填写sql语句
sprintf(sql_buff, "DELETE FROM student WHERE id=%d", id);
//执行sql语句
ret = sqlite3_exec(sql_db, sql_buff, NULL, NULL, NULL);
if (ret != SQLITE_OK)
{
perror("删除 失败");
printf("返回值[%d] 错误信息[%s]\n", ret, sqlite3_errmsg(sql_db));
exit(-1);
}
printf("学员信息删除成功\n");
return;
}
// 3. 修改
void update_student(sqlite3 *sql_db)
{
int id, score, ret;
char name[32];
printf("输入修改ID 更新姓名 成绩 : ");
scanf("%d %s %d", &id, name, &score);
char sql_buff[256] = {0};
//填写sql语句
/*
在代码中组装的sql语句本身就是一个字符串 如果某个字段的值是字符串类型
就需要用 单引号 '' 引起来 引号里面sql语句后面不用加分号
*/
sprintf(sql_buff, "UPDATE student SET name='%s',score=%d WHERE id=%d", name, score, id);
//执行sql语句
ret = sqlite3_exec(sql_db, sql_buff, NULL, NULL, NULL);
if (ret != SQLITE_OK)
{
perror("修改 失败");
printf("返回值[%d] 错误信息[%s]\n", ret, sqlite3_errmsg(sql_db));
exit(-1);
}
printf("学员信息修改成功\n");
return;
}
// 4. 查询所有学员---方法 1 :sqlite3_get_table
void search_student1(sqlite3 *sql_db)
{
int ret;
char sql_buff[256] = {0};
//填写sql语句
sprintf(sql_buff, "SELECT * FROM student");
char **result; // 结果集
int row = 0; // 行数
int column = 0; // 列数
/*
会将 查询的到的结果的 行数写到row的地址里 列数写到column的地址里
让 result 指向 sqlite3_get_table 申请的结果集的内存空间
*/
//查询结果的函数 /结果集 /行数 /列数 /错误信息
sqlite3_get_table(sql_db, sql_buff, &result, &row, &column, NULL);
if (ret != SQLITE_OK)
{
perror("查询 失败");
printf("返回值[%d] 错误信息[%s]\n", ret, sqlite3_errmsg(sql_db));
exit(-1);
}
/*---------------- 打印学员信息 ----------------*/
//打印表头
int i = 0;
for (i = 0; i < column; i++) // 列数
{
printf("%10s", result[i]);
}
printf("\n");
int keep_i = i; // 继续获取 结果集result[ ]内容
int j = 0;
for (j = 0; j < row; j++) //行数
{
for (i = 0; i < column; i++) // 列数
{
printf("\t%s", result[keep_i]);
keep_i++;
}
printf("\n");
}
printf("学员信息查询成功\n");
//释放 结果集 防止内存泄漏
sqlite3_free_table(result);
return;
}
// 4. 查询所有学员---方法 2 :callback 回调函数
int flag = 0; // 全局变量 标记表头是否打印
//回调函数
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; //打印之后 将标记flag=1 下次调用就不打印
}
//打印字段的值
for (i = 0; i < ncolumn; i++)
{
printf("\t%s", f_value[i]);
}
printf("\n");
return 0; //必须写返回值 否则报错
}
//
void search_student2(sqlite3 *sql_db)
{
int ret;
char sql_buff[256] = {0};
//填写sql语句
sprintf(sql_buff, "SELECT * FROM student");
//执行sql语句 /回调函数
ret = sqlite3_exec(sql_db, sql_buff, callback, NULL, NULL);
if (ret != SQLITE_OK)
{
perror("查询 失败");
printf("返回值[%d] 错误信息[%s]\n", ret, sqlite3_errmsg(sql_db));
exit(-1);
}
printf("学员信息查询成功\n");
flag = 0; //查询结束后 将标记flag = 0 方便下次查询使用
return;
}
my_sqlite3.h
#ifndef __MY_SQLITE_H__
#define __MY_SQLITE_H__
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
// 1. 数据库初始化 ---打开数据文件、建表
sqlite3 *proc_init(void);
// 1. 添加
void insert_student(sqlite3 *sql_db);
// 2. 删除
void delete_student(sqlite3 *sql_db);
// 3. 修改
void update_student(sqlite3 *sql_db);
// 4. 查询所有学员---方法 1 :sqlite3_get_table
void search_student1(sqlite3 *sql_db);
// 4. 查询所有学员---方法 2 :callback 回调函数
void search_student2(sqlite3 *sql_db);
#endif
执行结果
注意
1. 数据库初始化
建表
IF NOT EXISTS
表不存在则创建 表存在则直接使用,而不是报错
2. 添加
组装sql语句
双引号里面sql语句后面不用加分号
在代码中组装的sql语句本身就是一个字符串 如果某个字段的值是字符串类型
就需要用 单引号' '
引起来 ;
3. 对于删除的语句
即使 记录中没有满足WHERE
后面条件的
语句也会执行成功,只不过没有任何事情发生
4. 对于修改的语句
即使 记录中没有满足WHERE
后面条件的
语句也会执行成功,只不过没有任何事情发生
5.查询使用
callback
回调函数
每查询到一条记录callback
函数就会被调用一次
sqlite3_get_table()函数的 result 结果集
数据
- result
*查询结果为空时
row = 0 *行数为0
column = 0; *列数为0
sqlite3_exec的回调函数—callback
int (*callback)(void* arg ,int ncolumn ,char** f_value,char** f_name)
功能:
得到查询结果
参数:
arg 为回调函数传递参数使用的 --传递多个参数,使用结构体传参
ncolumn 记录中包含的字段的数目 --表的结构 字段数
f_value 包含每个字段值的指针数组 --字段值
f_name 包含每个字段名称的指针数组-字段名(表头)
返回值:
成功 0
出错 非0
callback 中的 f_value 和 f_name
f_value 和 f_name 都是指针数组,数组中的每个成员都是一个 char * 指针
数据
callback
回调函数 每当查询到一条记录 都会被调用用一次: