最近学习了数据库的简单操作,用到的数据库版本是sqlite3,并且运用数据库知识进行了学生管理系统的建立与操作,在这里分享我的所学所得:
目录
一、首先在Ubuntu中安装sqlite数据库
二、打开数据库文件
三、sqlite3数据库的操作
四、使用sqlite3实现学生管理系统
1.离线安装:
sudo dpkg -i libsqlite3-dev_3.22.0-1ubuntu0.4_amd64.deb sqlite3_3.22.0-1ubuntu0.4_amd64.deb
2.在线安装:
sudo apt-get install sqlite3 libsqlite3-dev
3.如何确定是否安装成功
在Ubuntu终端输入sqlite3,如果出现以下界面说明安装成功可以使用:
4.打开数据库的方式有两种:
(1)sqlite3 数据库文件名 (数据库文件名一般以 .db 结尾)
(2)先输入命令 sqlite3 进入sqlite命令行
再使用 .open 数据库文件名 打开
(数据库文件名一般以 .db 结尾 .open前有一个点符号不要忽略)
1.系统命令
sqlite3的系统命令都是以 . 开头,结尾不能加分号
不同的数据库系统命令一般不同
一般常用的sqlite3命令如下:
.help 打开帮助文档
.open 打开数据库文件
.quit 退出数据库程序 也可以是 .q
.exit 退出数据库程序
.tables 查看当前数据库文件中有哪些数据表
.schema 查看建表语句(表结构)的
.headers on|off 查询时是否显示表头信息
关于数据库文件、数据表、字段、表结构解释如图:
其中:学生信息表、任课教师表、学生成绩表:同一数据库文件(.db)中的多个数据表
id、name、sex :表的字段
1001、小马、89 :表中的一条记录
表结构就是如图所示这样,类似于一个excel表格
2.SQL语句
SQL语句是用来操作数据库文件的(增删改查等)
虽然不同数据库的系统命令不同,但是关系型数据库的SQL语句都是通用的。
SQL语句的关键字不分大小写,只是一般情况下关键字都是大写。
SQL语句和SQL命令相反 不以 . 开头,但是以 ;结尾。
具体SQL简单语句如下:
1.创建数据表(创建数据库文件时候,不会自动创建数据表,需要我们手动创建)
CREATE TABLE 表名(字段1 字段1类型, 字段2 字段2类型,..., 字段n 字段n类型);
字段类型:
整型 INT或者INTEGER
字符串 CHAR或者TEXT
例:
CREATE TABLE student(id INT, name CHAR, score INTEGER);
2.向表中插入数据
//1.完全赋值 这种方式需要要求必须从左到右给表的每个字段都赋值
INSERT INTO student VALUES(1001, "小关", 90);
//2.部分赋值 这种方式可以给指定的字段插入数据
INSERT INTO student(id,name) VALUES(1002,"小马");
3.查询表中的数据
//查询表中的所有字段以及信息记录
SELECT FROM student;
//只查询 id 和 name 字段 (将id,name 换成score也是一样的效果)
SELECT id,name FROM student;
//查询score为90的记录的所有字段
SELECT * FROM student WHERE score=90;
//查询name是 "小马" 的记录的所有字段 当执行SQL语句时,字符串要加上双引号或者单引号
SELECT * FROM student WHERE name="小马";
//也可以在查询时候用上 AND 和 OR 连接多个条件 AND为并且 OR为或者
SELECT * FROM student WHERE name="小关" AND score=90;
SELECT * FROM student WHERE score=90 OR score=100;
//查询的同时排序使用 ORDER BY 后跟排序要依据的数据
SELECT * FROM student ORDER BY score;//根据成绩排序(默认升序)
//排序也可以在SQL语句末尾处加上 ASC代表升序 DESC代表降序
//如果没加 默认为升序
4.修改表中的记录
//将表中 id 为1001 的成员的 score 修改为100
UPDATE student SET score=100 WHERE id=1001;
//注:修改命令的条件即使不成立(例如 修改一个不存在的成员的成绩) 也可以执行成功 但是看不到现象
//可以多个条件一起用
//将name为小关的成员的score修改为90,id修改为1099
UPDATE student SET score=90,id=1099 WHERE name="小关";
5.删除表中的记录
//在表中删除 name 为张三的记录
DELETE FROM student WHERE name='张三';
//注:即使条件不成立 也能执行成功 但是看不到现象 和修改表中记录一样
//多个条件一起用
//在表中删除 name 为张三的 或者 score为60 的记录
DELETE FROM student WHERE name="赵六" OR score=60;
6.删除数据表
DROP TABLE 表名;
3.sqlite3常用API接口
注意:sqlite3函数的头文件为 sqlite3.h
编译时需要链接sqlite3的库 -lsqlite3
常用API接如下:
1.打开数据库文件:
函数原型:
int sqlite3_open(const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppdb); /* OUT: SQLite db handle */
功能:
打开一个数据库文件(存在直接打开 不存在就新建并打开)
参数:
filename 数据库名字
ppdb 操作数据库的指针,数据库句柄
返回值:
成功返回 SQLITE_OK
失败返回 error_code
2.获取错误信息的函数
函数原型:
const char *sqlite3_errmsg(sqlite3* db);
功能:
获取最后一次错误信息描述
3.执行sql语句的函数
函数原型:
int sqlite3_exec(sqlite3* db, const char *sql,
int (*callback)(void*,int,char**,char**),
void * arg, char **errmsg);
功能:
执行sql语句
参数:
db 数据库的句柄指针
sql 将要被执行sql语句
callback 回调函数, 只有在查询语句时使用 其他情况可以传NULL
arg 为callback 传参的,如果不是查询语句 也可以传NULL
errmsg 错误信息的地址
(如果使用了这个参数,要记得使用 sqlite3_free 去释放空间)
返回值:
成功返回SQLITE_OK
失败返回errcode 错误码
4.关于sqlite3_exec函数的回调函数callback
函数原型:
int callback(void* arg ,int ncolumn ,char** f_value,char** f_name)
功能:
得到查询结果f_value f_name
参数:
arg 为回调函数传递参数使用的 不需要参数可以传NULL
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);
功能:
查询数据库,它会创建一个新的内存区域来存放查询的结果信息
参数:
db 数据库操作句柄
zSql 数据库的sql语句
azResult 查询的结果
nRow 行数
nColumn 列数
errmsg 错误消息
返回值:
成功返回0
失败返回错误码errcode
//用此函数必须使用指定函数进行释放
//释放由sqlite3_get_table产生的结果集
函数原型:
sqlite3_free_table(azResult);
4.关闭数据库的函数
函数原型:
int sqlite3_close(sqlite3* db);
功能:
关闭一个数据库
#include
#include
#include
#define DATABASE "hqyj.db"
//进程初始化的函数
int proc_init(sqlite3** p)
{
//打开数据文件
int ret = 0;
char* errmsg = NULL;
if (SQLITE_OK != (ret = sqlite3_open(DATABASE, p))) {
printf("文件 %s 的第 %d 行出错,错误码[%d],错误信息[%s]\n",
__FILE__, __LINE__, ret, sqlite3_errmsg(*p));
exit(-1);
}
printf("数据库文件打开成功..\n");
//尝试创建数据表
//代码中sql语句可以不写分号
// IF NOT EXISTS 表示 如果不存在则创建 如果存在 则直接打开而不是报错
char sqlstr[256] = "CREATE TABLE IF NOT EXISTS student(id INT PRIMARY KEY, name CHAR, score INT)";
if (SQLITE_OK != (ret = sqlite3_exec(*p, sqlstr, NULL, NULL, &errmsg))) {
printf("文件 %s 的第 %d 行出错,错误码[%d],错误信息[%s]\n",
__FILE__, __LINE__, ret, errmsg);
exit(-1);
}
printf("数据表打开成功..\n");
//释放errmsg
sqlite3_free(errmsg);
return 0;
}
//添加学员信息的函数
void insert_student(sqlite3* my_db)
{
int input_id = 0;
char input_name[32] = { 0 };
int input_score = 0;
printf("请输入新学员的id(INT):");
scanf("%d", &input_id);
printf("请输入新学员的name(CHAR):");
scanf("%s", input_name);
printf("请输入新学员的score(INT):");
scanf("%d", &input_score);
//组装sql语句
int ret = 0;
char sqlstr[256] = { 0 };
//在字符串的sql语句中再想使用引号时 使用单引号即可
sprintf(sqlstr, "INSERT INTO student VALUES(%d, '%s', %d)", input_id, input_name, input_score);
//调试数据库代码时 第一件事儿 先把要执行的sql语句打印出来
// printf("yangfs sql:[%s]\n", sqlstr);
//执行sql语句
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlstr, NULL, NULL, NULL))) {
printf("文件 %s 的第 %d 行出错,错误码[%d],错误信息[%s]\n",
__FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("新学员信息插入成功..\n");
}
//修改学员信息的函数
void modify_student(sqlite3* my_db)
{
//根据id修改学生的信息
int modify_id = 0;
char modify_name[256] = { 0 };
int modify_score = 0;
printf("请输入要修改的学员的id(INT):");
scanf("%d", &modify_id);
printf("请输入修改之后的学员的姓名name(CHAR):");
scanf("%s", modify_name);
printf("请输入修改之后的学员的成绩score(INT):");
scanf("%d", &modify_score);
//组装sql语句
int ret = 0;
char sqlstr[256] = { 0 };
sprintf(sqlstr, "UPDATE student SET name='%s',score=%d WHERE id=%d", modify_name, modify_score, modify_id);
printf("ghj sql:[%s]\n", sqlstr);
//执行sql语句
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlstr, NULL, NULL, NULL))) {
printf("文件 %s 的第 %d 行出错,错误码[%d],错误信息[%s]\n",
__FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("学员信息修改成功..\n");
}
//删除学员信息的函数
void delete_student(sqlite3* my_db)
{
//根据id删除学生的信息
int delete_id = 0;
printf("请输入要删除的学员的id(INT):");
scanf("%d", &delete_id);
//组装sql语句
int ret = 0;
char sqlstr[256] = { 0 };
sprintf(sqlstr, "DELETE student WHERE id=%d", delete_id);
printf("ghj sql:[%s]\n", sqlstr);
//执行sql语句
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlstr, NULL, NULL, NULL))) {
printf("文件 %s 的第 %d 行出错, 错误码为[%d],错误信息为[%s]\n",
__FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
exit(-1);
}
printf("删除学员成功..\n");
}
int flag = 0; //控制打印表头的标志位 0需要打印 1不需要打印
// callback 回调函数
int callback(void* arg, int ncolumn, char** f_value, char** f_name)
{
int i = 0;
//先打印表头
if (flag == 0) {
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; //必须写return 0 不然会报错query aborted
}
//查询学员信息的函数---基于callback实现
void search_student_1(sqlite3* my_db)
{
printf("\n");
//组装sql语句
char sqlstr[256] = { 0 };
int ret = 0;
sprintf(sqlstr, "SELECT * FROM student");
//执行sql语句
if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlstr, callback, NULL, NULL))) {
printf("文件 %s 的第 %d 行出错, 错误码为[%d],错误信息为[%s]\n",
__FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
exit(-1);
}
flag = 0; //重置打印表头的标志位
printf("学员信息查询成功..\n");
}
//查询学员信息的函数---基于sqlite3_get_table实现
void search_student_2(sqlite3 *my_db){
printf("\n");
char **result = NULL;
int nrow = 0;
int ncolumn = 0;
//组装sql语句
int ret = 0;
char sqlstr[256] = {0};
sprintf(sqlstr,"SELECT * FROM student");
if(SQLITE_OK != (ret = sqlite3_get_table(my_db,sqlstr,&result,&nrow,&ncolumn,NULL))){
printf("文件 %s 的第 %d 行出错,错误码[%d],错误信息[%s]\n",\
__FILE__, __LINE__, ret, sqlite3_errmsg(my_db));
exit(-1);
}
//先打印表头
int i = 0;
int j = 0;
for(i = 0;i