5-1. SQL
第一部分:SQL的起源与设计哲学
- 理论基础:SQL基于关系代数和关系演算,目标是让数据库访问变得简单直观。
- 声明式语言:用户只需描述"想要什么",而不需要指定"如何获取"。这与网状/层次模型的"过程式"导航形成鲜明对比。
- 历史发展:
- SEQUEL:IBM在1970年代开发的早期版本。
- SQL:标准化后成为"Structured Query Language"。
- 标准化:经过ANSI、ISO等组织标准化,形成了我们今天使用的SQL。
第二部分:SQL语言概览
| 类别 | 全称 | 主要命令 | 作用 |
|---|---|---|---|
| DDL | 数据定义语言 | CREATE, ALTER, DROP, TRUNCATE | 定义和修改数据库结构 |
| DML | 数据操作语言 | INSERT, UPDATE, DELETE, MERGE | 操作数据库中的实际数据 |
| DQL | 数据查询语言 | SELECT (带有各种子句) | 查询和检索数据 |
| DCL | 数据控制语言 | GRANT, REVOKE | 控制访问权限 |
| TCL | 事务控制语言 | COMMIT, ROLLBACK, SAVEPOINT | 管理事务 |
第三部分:DDL深度解析
CREATE TABLE与约束
CREATE TABLE Students (
sno VARCHAR(10) PRIMARY KEY, -- 主键约束
sname VARCHAR(50) NOT NULL, -- 非空约束
gender CHAR(1) CHECK (gender IN ('M', 'F')), -- 检查约束
dorm_no VARCHAR(5),
room_no VARCHAR(4),
-- 复合主键
PRIMARY KEY (dorm_no, room_no),
-- 外键约束
FOREIGN KEY (dorm_no, room_no) REFERENCES Rooms(dorm_no, room_no)
);
约束类型详解: - PRIMARY KEY:主键,唯一标识 + 非空 - UNIQUE:唯一约束,允许NULL值 - NOT NULL:非空约束
- CHECK:检查条件约束 - FOREIGN KEY:外键约束,维护引用完整性
第四部分:DML与DQL精讲
单表查询的完整结构
执行顺序(重要!): FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
多表查询的三种方式
-
显式连接(推荐)
-
自然连接
-
隐式连接(传统方式)
聚集查询与分组
基础聚集函数: - COUNT(*) - 统计行数 - COUNT(属性) - 统计非空值 - AVG(), SUM(), MAX(), MIN()
分组查询的要点: - GROUP BY 后面的属性必须出现在 SELECT 中(或者是聚集函数的参数) - WHERE 在分组前过滤,HAVING 在分组后过滤
示例:查询每个宿舍的学生人数(只显示超过5人的宿舍)
SELECT dorm_no, COUNT(*) as student_count
FROM Students
WHERE gender = 'M' -- 分组前过滤:只考虑男生
GROUP BY dorm_no
HAVING COUNT(*) > 5; -- 分组后过滤:只显示人数>5的宿舍
第五部分:深刻问题解答
问题1:关系数据库Primary Key vs 文档数据库ID机制
| 特性 | 关系数据库Primary Key | 文档数据库ID |
|---|---|---|
| 定义方式 | 用户显式定义,有业务含义 | 系统自动生成,通常无业务含义 |
| 组成 | 可以是单个属性或复合属性 | 通常是单个ID字段 |
| 业务语义 | 具有业务意义(学号、身份证号等) | 通常无业务意义,纯技术标识 |
| 稳定性 | 相对稳定,变更影响大 | 稳定不变 |
| 查询模式 | 可通过业务属性直接查询 | 通常需要通过ID查询 |
优缺点分析: - Primary Key优点:有业务含义,支持基于业务属性的直接访问,数据关系清晰 - Primary Key缺点:设计复杂,变更困难,可能存在业务属性不稳定问题 - ID机制优点:简单统一,性能优化容易,稳定性好 - ID机制缺点:缺乏业务含义,查询模式受限
现代实践:很多关系数据库同时支持自增ID(代理键)和业务主键,结合两者优点。
问题2:预定义模式 vs 无模式的原因
根本原因:数据模型和设计哲学的不同
| 方面 | 关系数据库 | 文档数据库 |
|---|---|---|
| 理论基础 | 关系代数,强调结构一致性 | 面向文档,强调灵活性 |
| 设计目标 | 数据一致性、完整性、减少冗余 | 开发敏捷性、处理异构数据 |
| 数据特征 | 结构化数据,模式相对稳定 | 半结构化数据,模式频繁变化 |
| 约束维护 | 数据库级别强制约束 | 应用级别处理约束 |
| 使用场景 | 事务处理、复杂查询、关键业务数据 | 内容管理、日志数据、快速原型开发 |
背后的权衡: - 严格模式 换来了 数据质量保证 和 查询优化能力 - 灵活模式 换来了 开发速度 和 适应变化的能力
问题3:数据库如何检测重复插入
技术实现:索引机制
- 创建唯一索引:
- 当定义
PRIMARY KEY或UNIQUE约束时,数据库自动在后台创建唯一索引 -
这个索引通常使用B+树等数据结构实现
-
插入时的检测过程:
-
性能优化:
- 索引使得查找操作的时间复杂度为O(log n),而不是O(n)
-
即使表中有上亿条记录,也能快速完成重复性检查
-
事务考虑:
- 在事务中,数据库还需要检查其他未提交的事务是否插入了相同键值
- 这通过锁机制或多版本并发控制(MVCC)来实现
示例:如果你在sno上定义了主键,当插入('1001', '张三')时,数据库会在sno的B+树索引中查找1001,如果找到就拒绝插入。