1、数据库
高效对大批量数据进行存储、管理、查询和维护的软件系统(核心是 "数据管理")
1.1 分类
- 关系型数据库(基于二维表结构,支持 SQL)
- Oracle(企业级商用)
- Mysql(开源主流)
- SQLServer(微软商用)
- SQLite(轻量级嵌入式)
- 非关系型数据库(NoSQL)不是传统表格模型的数据库
- Redis(键值对型)
1.2 SQLite数据库
- 轻量级嵌入式关系型数据库,无需独立服务进程
- 支持标准SQL编程语言,跨平台,单文件存储数据库
- 所有数据库支持:SQL编程语言
1.3 SQLite数据库的安装
- 虚拟机网络连通
- apt-get工具集配置成功
- 安装SQlite软件
bash
# 安装sqlite3核心工具
sudo apt-get install sqlite3
# 安装sqlite3开发库(C/C++编程用)
sudo apt-get install libsqlite3-dev
# 安装可视化管理工具
sudo apt-get install sqlitebrowser
Navicat 是通用数据库可视化工具(支持 SQLite)
- 运行sqlite3
bash
sqlite3
.quit //退出
//如下:
linux@spring:~$ sqlite3 # 启动sqlite3(默认内存数据库)
SQLite version 3.22.0 2018-01-22 18:45:57
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .quit # 退出(补充:.exit 也可退出)
linux@spring:~$
//.open test.db 可打开 / 创建名为 test.db 的本地数据库文件(持久化存储)
1.4 Sqlite 特有命令(以.开头,区分 SQL 语句)
| 命令 | 功能说明 |
|---|---|
| .databases | 列出附加数据库的名称和文件路径 |
| .header(s) ON | OFF | 开启 / 关闭查询结果的列名头部(ON 显示列名,OFF 不显示) |
| .mode MODE | 设置数据显示格式,常用: - csv:逗号分隔 - column:列对齐(常用) - line:每行一个字段 - list:默认,竖线分隔 - table:表格形式(最易读) |
| .schema [TABLE] | 显示表的创建语句(不加 TABLE 则显示所有表) |
| .quit / .exit | 退出 sqlite3 终端 |
| .tables | 查看数据库中所有表名 |
| .show | 查看当前终端配置(如 mode、header 等) |
1.5 SQL 核心语句(必须以;结尾)
1.5.1 创建表(create table)
sql
CREATE TABLE 表名称
(
列名称1 数据类型,
列名称2 数据类型,
列名称3 数据类型,
....
);
-- 规范:字段名建议用英文(避免中文乱码),补充注释和约束
create table student (
id integer primary key asc, -- 学号(主键,自增)
name text not null, -- 姓名(非空)
gender text check(gender in ('男','女')), -- 性别(约束只能是男/女)
age integer check(age > 0), -- 年龄(约束大于0)
score integer default 0 -- 成绩(默认值0)
);
--eg:
create table student (id integer primary key asc, name text, gender text,
age integer, score integer);
1.5.2 删除表(drop table)
bash
-- 基础语法
drop table if exists student; -- 补充if exists,避免表不存在时报错
drop table if exists student;
1.5.3 插入数据(insert into)
sql
-- 向表格中插入新的行:
INSERT INTO 表名称 VALUES (值1, 值2,....);
insert into student values (1002, "李四", "女", 13, 80);
指定所要插入数据的列:
INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
-- 全字段插入(顺序与表结构一致)
insert into student (id, name, gender, age, score)
values (1, '张三', '男', 18, 85);
-- 省略主键(自增字段)
insert into student (name, gender, age, score)
values ('李四', '女', 19, 90), ('王五', '男', 18, 59); -- 批量插入
-- 插入默认值
insert into student (name, gender) values ('赵六', '男'); -- 成绩默认0
1.5.4 删除数据(delete from)
sql
删除某行:
DELETE FROM 表名称 WHERE 列名称 = 值
删除所有行:
DELETE FROM table_name / DELETE * FROM table_name
-- 删除符合条件的数据(慎用无where的删除!)
delete from student where score < 60; -- 删除不及格的学生
delete from student where id = 3; -- 删除指定学号的学生
-- 清空表(保留表结构,自增主键重置)
delete from student; -- 自增主键不重置
1.5.5 更新数据(update)
sql
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值;
UPDATE Person SET FirstName = 'Fred' WHERE LastName = 'Wilson'
UPDATE Person SET Address = 'Zhongshan 23', City = 'Nanjing' WHERE LastName = 'Wilson'
-- 修改符合条件的数据
update student set score = 60 where score < 60; -- 不及格的都改60
-- 批量修改多个字段
update student set age = 20, score = 88 where name = '张三';
1.5.6 查询数据(select)
基础语法 :select 字段1,字段2... from 表名 where 条件;
sql
-- 查询所有字段
select * from student;
-- 查询指定字段
select id, score from student;
-- 带条件查询(运算符)
select name from student where score < 60 and gender = '男'; -- 原笔记引号统一为单引号
-- 模糊查询(like)
select name from student where name like '%张%'; -- 包含"张"的姓名
-- 范围查询(between)
select name from student where score between 60 and 80; -- 60≤成绩≤80
-- 如果 column 的值等于值1、值2、值3中的任意一个,条件成立
SELECT * FROM table WHERE column IN (值1, 值2, 值3);
-- 等价于:
SELECT * FROM table
WHERE column = 值1 OR column = 值2 OR column = 值3;
运算符补充:
| 运算符 | 描述 |
|---|---|
| = | 等于 |
| <> / != | 不等于 |
| > / < | 大于 / 小于 |
| >= / <= | 大于等于 / 小于等于 |
| BETWEEN ... AND ... | 在范围内 |
| LIKE | 模糊匹配 |
| IN | 匹配多个值 |
| AND / OR | 多条件连接 |
1.5.7 排序(order by)
sql
ORDER BY 语句用于根据指定的列对结果集进行排序
-- desc:降序(从高到低),asc:升序(默认,可省略)
select id, name from student where score > 60 order by score desc;
select id, name from student where score > 60 order by score; -- 等价于asc
-- 多字段排序(先按成绩降序,再按年龄升序)
select id, name from student order by score desc, age asc;
-- 1. 先按 score 从高到低排序(降序)
-- 2. 当 score 相同时,再按 age 从小到大排序(升序)
1.6 SQLite 数据类型
SQLite 采用 "动态类型",常用核心类型:
因为类型是跟数据走的,不是跟列绑定的
sql
-- 创建表时写的类型只是"建议"
CREATE TABLE student (
id INTEGER, -- 建议存整数
name TEXT, -- 建议存文本
age INTEGER -- 建议存整数
);
-- 但我可以"不听话"
INSERT INTO student VALUES ('abc', 123, '18');
-- id列存了字符串,name列存了整数,age列存了字符串
-- 查看实际类型
SELECT id, typeof(id), name, typeof(name), age, typeof(age)
FROM student;
id | typeof(id) | name | typeof(name) | age | typeof(age)
----|------------|------|--------------|-----|------------
abc | text | 123 | integer | 18 | text
| 类型 | 说明 | 对应常规类型 | 例子 |
|---|---|---|---|
| INTEGER | 整型(整数,含自增) | int | 42, -100, 0 |
| REAL | 浮点型(小数) | float/double | 3.14, 2.0e10 |
| TEXT | 文本型(字符串) | varchar | 'hello', "world" |
| BLOB | 二进制型 | 图片 / 文件等 | x'ABCDEF' |
| NULL | 空值 | NULL |
NULL |
1.7 多表联合查询
1.7.1 交叉连接(cross join)
笛卡尔积:两表所有行两两组合(无实际业务意义,慎用)
sql
select si.name as 姓名, c.cname as 课程
from student_info si cross join course c; -- 别名简化(si=student_info,c=course)
1.7.2 内连接(inner join)
只返回两表匹配的行(最常用)
sql
select si.name as 姓名, s.score as 成绩
from student_info si inner join score s
on si.id = s.stu_id; -- 连接条件:学生学号=成绩表学号
1.7.3 外连接(outer join)
- 左外连接(left join):返回左表所有行,右表无匹配则为 NULL(常用)
- 右外连接(right join):SQLite 不支持,可通过左连接互换表实现
sql
select si.name as 姓名, s.score as 成绩
from student_info si left join score s
on si.id = s.stu_id; -- 即使学生无成绩,也会显示姓名,成绩为NULL
1.7.4 三表联合查询
sql
select si.name as 姓名, c.cname as 课程, s.score as 成绩
from student_info si
left join score s on si.id = s.stu_id
left join course c on s.cid = c.cid
where s.score > 60 -- 筛选及格的成绩
order by s.score desc;
1.8 数据库编程(C 语言接口)
1.8.1 sqlite3_open
- 函数原型:
cpp
int sqlite3_open(
const char *filename, /* 数据库文件路径(UTF-8):":memory:"=内存数据库,"test.db"=本地文件 */
sqlite3 **ppDb /* 输出参数:数据库句柄的指针 */
);
- 功能:打开 / 创建数据库,获取操作数据库的句柄
- 返回值:
- 成功:
SQLITE_OK(宏定义,值为 0) - 失败:错误码(如
SQLITE_CANTOPEN),可通过sqlite3_errmsg获取对应的英文错误描述
- 成功:
1.8.2 sqlite3_errmsg
- 函数原型:
cpp
const char *sqlite3_errmsg(sqlite3* db);
- 功能:传入数据库句柄,返回当前错误的英文描述字符串
- 示例:fprintf(stderr, "fail to sqlite3_exec:%s\n", perrmsg);
1.8.3 sqlite3_exec
- 函数原型:
cpp
int sqlite3_exec(
sqlite3* db, /* 已打开的数据库句柄 */
const char *sql, /* 要执行的SQL语句(以;结尾) */
int (*callback)(void*,int,char**,char**), /* 回调函数(仅select需要) */
void *arg, /* 传给回调函数的自定义参数 */
char **errmsg /* 输出参数:错误信息(需用sqlite3_free释放) */
);
- 功能:执行任意 SQL 语句(增删改查)
- 回调函数说明(select时处理查询结果):
cpp
// 参数:arg=自定义参数,col_num=select命令生成新表的列数,col_values=所有列数据字符串的指针数组名,col_names=所有列名称字符串的指针数组名
int callback(void *arg, int col_num, char **col_values, char **col_names) {
for (int i=0; i<col_num; i++) {
printf("%s = %s\n", col_names[i], col_values[i] ? col_values[i] : "NULL");
}
return 0; // 返回0继续处理下一行,非0终止查询
}
- 返回值:成功返回
SQLITE_OK,失败返回错误码
1.8.4 sqlite3_close
- 函数原型:
cpp
int sqlite3_close(sqlite3* db);
- 功能:关闭数据库句柄,释放资源
- 注意:需确保所有 SQL 操作完成后调用,否则返回
SQLITE_BUSY
1.8.5 sqlite3_free
- 函数原型:
cpp
void sqlite3_free(void* ptr);
- 功能:释放 sqlite3 分配的内存(如
sqlite3_exec的 errmsg 参数) - 示例:sqlite3_free(errmsg);
1.8.6 示例
cpp
#include <stdio.h>
#include <sqlite3.h>
// 回调函数:处理select查询结果
int select_callback(void *arg, int col_num, char **col_values, char **col_names) {
printf("--- %s ---\n", (char*)arg);
for (int i=0; i<col_num; i++) {
printf("%-8s: %s\n", col_names[i], col_values[i] ? col_values[i] : "NULL");
}
return 0;
}
int main() {
sqlite3 *db = NULL;
char *errmsg = NULL;
int ret;
// 1. 打开数据库
ret = sqlite3_open("test.db", &db);
if (ret != SQLITE_OK) {
printf("打开数据库失败:%s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return -1;
}
// 2. 创建表
char *create_sql = "create table if not exists student (id integer primary key autoincrement, name text, score integer);";
ret = sqlite3_exec(db, create_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
printf("创建表失败:%s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return -1;
}
// 3. 插入数据
char *insert_sql = "insert into student (name, score) values ('张三', 85), ('李四', 90);";
ret = sqlite3_exec(db, insert_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
printf("插入数据失败:%s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return -1;
}
// 4. 查询数据
char *select_sql = "select * from student;";
ret = sqlite3_exec(db, select_sql, select_callback, (void*)"学生信息", &errmsg);
if (ret != SQLITE_OK) {
printf("查询数据失败:%s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return -1;
}
// 5. 关闭数据库
sqlite3_close(db);
return 0;
}