Skip to content

第三章 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 根据功能可分为以下几类:

  1. 数据定义语言 (DDL):用于定义和管理数据库对象的结构。
    • 主要语句:CREATE、ALTER、DROP、TRUNCATE。
  2. 数据操纵语言 (DML):用于对表中的数据进行增删改查。
    • 主要语句:INSERT、UPDATE、DELETE、SELECT。
  3. 数据控制语言 (DCL):用于权限管理。
    • 主要语句:GRANT(授权)、REVOKE(撤销权限)。
  4. 事务控制语言 (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 操作)。

需区分三个相关操作:

  • DROPTABLE:删除表结构及数据。
  • DELETEFROMtable:删除表中的数据,表结构保留,操作可回滚,会触发触发器。
  • TRUNCATETABLE:清空表数据,表结构保留,不可回滚,速度比 DELETE 快,不触发行级触发器。

2.4 索引的创建与管理 ​

索引是提升查询性能的核心手段。其作用在于通过建立额外的数据结构(如 B+ 树、哈希表),使 DBMS 无需逐行扫描整张表即可快速定位目标数据。

sql
CREATE INDEX idx_sname ON Student(Sname);          -- 普通索引
CREATE UNIQUE INDEX idx_sno ON Student(Sno);       -- 唯一索引
  • 单列索引与联合索引:联合索引的使用需遵循最左前缀匹配原则——查询条件必须从联合索引的最左列开始,才能有效利用该索引。
  • 索引的代价:虽然索引能加速查询,但每次 INSERT、UPDATE、DELETE 操作时都需要同步维护索引,因此不宜对频繁修改的列建立过多索引。

3. 数据操纵 (DML) 基础 ​

3.1 插入数据 (INSERT) ​

3.2 更新数据 (UPDATE) ​

3.3 删除数据 (DELETE) ​

4. 数据查询 (SELECT) 详解 ​

4.1 基本查询 ​

4.2 条件查询 (WHERE) ​

4.3 聚合函数与分组查询 (GROUP BY, HAVING) ​

4.4 排序 (ORDER BY) ​

4.5 连接查询 (JOIN) ​

内连接 (INNER JOIN) ​

左外连接 (LEFT OUTER JOIN) ​

自连接 (Self Join) ​

4.6 子查询 (Subqueries) ​

标量子查询 ​

使用 IN 的子查询 ​

使用 EXISTS 的相关子查询 ​

IN 与 EXISTS 的选择 ​

4.7 集合操作 ​

5. 视图 (Views) ​

5.1 视图的创建与使用 ​

5.2 视图的作用 ​

5.3 视图的更新限制 ​

6. 窗口函数 (Window Functions) ​

6.1 基本语法 ​

6.2 常用窗口函数 ​

7. 公用表表达式 (CTE) 与递归查询 ​

8. 数据库编程 ​

8.1 存储过程 (Stored Procedures) ​

8.2 触发器 (Triggers) ​

8.3 游标 (Cursors) ​

8.4 嵌入式 SQL (Embedded SQL) ​

9. 数据控制 (DCL) ​

9.1 权限管理 ​