主题
第三章 SQL 语言详解
1. SQL 概述
结构化查询语言 (SQL, Structured Query Language) 是关系型数据库的标准语言。它不同于 C、Java 等过程式编程语言——SQL 是一种声明式 (Declarative) 语言,用户只需描述"需要什么样的数据",而无需指定"如何获取数据"的具体步骤。底层的查询路径选择由 DBMS 的查询优化器自动完成。
也正因为 SQL 是声明式语言,学习 SQL 时最容易出现两种偏差。第一种偏差是把它当成关键字清单,只记语法模板,不理解每个子句在结果语义中承担什么作用;第二种偏差是只追求“语句能跑出来”,却忽略结果口径、执行代价和协作可维护性。真正成熟的 SQL 能力,既包括把业务问题准确翻译成查询结构,也包括判断这条语句在真实系统中是否稳定、安全、可读。换句话说,SQL 既是一门语言,也是一种工程接口。
1.1 SQL 的标准化历程
SQL 经过多次标准化修订,主要版本包括:
- SQL-86 / SQL-89:最初的工业标准,确立了
SELECT-FROM-WHERE的基本框架。 - SQL-92:目前兼容性最广泛的版本,引入了外连接语法(
LEFT/RIGHT JOIN)、子查询等特性。 - SQL:1999:引入了公用表表达式 (CTE)、递归查询、触发器标准和布尔类型。
- SQL:2003:引入了窗口函数 (Window Functions),极大增强了分析查询能力。
- 后续版本:陆续增加了对 JSON、XML、时序数据等的支持。
1.2 SQL 语言的功能分类
SQL 根据功能可分为以下几类:
- 数据定义语言 (DDL):用于定义和管理数据库对象的结构。
- 主要语句:
CREATE、ALTER、DROP、TRUNCATE。
- 主要语句:
- 数据操纵语言 (DML):用于对表中的数据进行增删改查。
- 主要语句:
INSERT、UPDATE、DELETE、SELECT。
- 主要语句:
- 数据控制语言 (DCL):用于权限管理。
- 主要语句:
GRANT(授权)、REVOKE(撤销权限)。
- 主要语句:
- 事务控制语言 (TCL):用于管理事务的提交和回滚。
- 主要语句:
COMMIT、ROLLBACK、SAVEPOINT。
- 主要语句:
NOTE
SELECT 有时被单独称为数据查询语言 (DQL),但在广义的 DML 分类中通常将其包含在内。
2. 数据定义 (DDL)
2.1 创建表
使用 CREATE TABLE 语句定义表的结构,包括列名、数据类型和各种约束条件。
sql
CREATE TABLE Student (
Sno CHAR(9) PRIMARY KEY, -- 主键约束
Sname CHAR(20) NOT NULL, -- 非空约束
Ssex CHAR(2),
Sage SMALLINT CHECK (Sage >= 0 AND Sage <= 150), -- CHECK 约束
Sdept CHAR(20)
);常见的列级约束包括:
- PRIMARY KEY:主键约束,保证实体完整性。主键值不能为 NULL 且不能重复。
- NOT NULL:非空约束。
- UNIQUE:唯一性约束,允许存在一个 NULL 值(取决于具体 DBMS 实现)。
- CHECK:检查约束,限定列值的合法范围。
- DEFAULT:为列指定默认值。
表级约束可以在列定义之后统一声明,适用于联合主键或外键:
sql
CREATE TABLE SC (
Sno CHAR(9),
Cno CHAR(4),
Grade SMALLINT,
PRIMARY KEY (Sno, Cno), -- 联合主键
FOREIGN KEY (Sno) REFERENCES Student(Sno) -- 外键约束
ON DELETE CASCADE -- 级联删除
ON UPDATE CASCADE -- 级联更新
);建表语句之所以在 SQL 学习中格外重要,是因为它决定了后续所有增删改查的语义边界。很多初学者更喜欢先学查询,觉得建表只是“把字段列出来”,其实恰恰相反。表结构一旦设计粗糙,后面再复杂的查询也只能在模糊结构上打补丁。主键决定对象如何被唯一识别,数据类型决定值能以什么形式进入系统,约束决定哪些非法状态在入口就被挡住。数据库系统之所以可靠,首先不是因为查询写得漂亮,而是因为从第一条 CREATE TABLE 开始就把边界定义清楚了。
选择数据类型时,也不能只看“能不能存进去”,而要看它是否与业务语义一致。年龄字段用整数、金额字段用精确小数、状态字段用受限枚举或字典引用、时间字段明确时区语义,这些都属于设计阶段必须提前想清楚的问题。若图省事把大量字段都做成字符串,短期内可能觉得灵活,长期就会在排序错误、比较失真、索引失效和统计口径混乱中付出更高代价。SQL 教材之所以反复强调类型,不是形式主义,而是在帮助学习者建立“结构先于操作”的思维。
2.2 修改表结构
使用 ALTER TABLE 语句对已有的表结构进行调整:
- 添加新列:
ALTER TABLE Student ADD S_entrance DATE; - 修改列的数据类型:
ALTER TABLE Student ALTER COLUMN Sage INT; - 添加约束:
ALTER TABLE Student ADD CONSTRAINT ck_age CHECK (Sage >= 0); - 删除约束:
ALTER TABLE Student DROP CONSTRAINT ck_age;
ALTER TABLE 之所以值得单独强调,是因为它代表数据库进入持续演进阶段。真实系统几乎不可能永远保持第一次建表时的结构不变,字段会新增,含义会扩展,约束会收紧,索引也会跟着访问模式调整。也正因为结构会变化,修改表结构时不能只盯着语法是否正确,还要考虑旧数据如何迁移、默认值如何补齐、是否会触发大表锁定、上层应用是否已经适配。数据库结构变更不是普通文本编辑,而是一次对线上数据契约的正式修改。
2.3 删除表
DROP TABLE Student; 会同时删除表的结构定义和所有数据,该操作不可回滚(因为它属于 DDL 操作)。
需区分三个相关操作:
:删除表结构及数据。 :删除表中的数据,表结构保留,操作可回滚,会触发触发器。 :清空表数据,表结构保留,不可回滚,速度比 DELETE快,不触发行级触发器。
2.4 索引的创建与管理
索引是提升查询性能的核心手段。其作用在于通过建立额外的数据结构(如 B+ 树、哈希表),使 DBMS 无需逐行扫描整张表即可快速定位目标数据。
sql
CREATE INDEX idx_sname ON Student(Sname); -- 普通索引
CREATE UNIQUE INDEX idx_sno ON Student(Sno); -- 唯一索引- 单列索引与联合索引:联合索引的使用需遵循最左前缀匹配原则——查询条件必须从联合索引的最左列开始,才能有效利用该索引。
- 索引的代价:虽然索引能加速查询,但每次
INSERT、UPDATE、DELETE操作时都需要同步维护索引,因此不宜对频繁修改的列建立过多索引。
