比较与范围
=、>、BETWEEN AND
把自然语言问题组合成结果关系
一个 SQL 查询先从输入关系形成结果关系,再用连接、嵌套、集合和派生表组合更复杂的条件
FROM 提供输入关系,WHERE 筛选元组,SELECT 形成结果列
01
02
03SELECT Sname, Smajor
FROM Student
WHERE Smajor = '信息安全';投影改变列,DISTINCT 决定结果中是否消除重复
| 写法 | 结果语义 | 适用判断 |
|---|---|---|
SELECT Sno FROM SC | 选出每条选课记录的学号 | 同一学生可出现多次 |
SELECT DISTINCT Sno FROM SC | 只保留不同学号 | 需要学生集合 |
SELECT Sname AS name FROM Student | 选择列并改结果列标题 | 结果需要更清楚的列名 |
SELECT * FROM Student | 选择全部列 | 临时查看或探索数据 |
关系代数常按集合理解,SQL 默认保留重复行
WHERE 先筛选单个元组,聚集结果由 HAVING 筛选
=、>、BETWEEN AND
IN、NOT IN、LIKE
AND、OR、NOT
IS NULL、IS NOT NULL;三值逻辑留到 3.5
WHERE 先于分组作用于元组
ORDER BY 作用于查询结果,LIMIT 控制返回行数
01
02
03
04
05
06-- MySQL 8.4 常见分页语法
SELECT Sno, Grade
FROM SC
WHERE Cno = '81003'
ORDER BY Grade DESC, Sno ASC
LIMIT 10 OFFSET 0;| 子句 | 作用 |
|---|---|
ORDER BY Grade DESC | 按成绩降序排列结果 |
LIMIT 10 | 只返回前 10 行 |
LIMIT 5 OFFSET 2 | 跳过 2 行后返回 5 行 |
先得到满足条件的结果,再决定显示顺序与窗口;LIMIT/OFFSET 是 MySQL 常见语法,分页要有稳定的次排序列
没有分组时,聚集函数作用于整个满足条件的结果
01
02
03SELECT COUNT(*) AS enrollment_count
FROM SC
WHERE Semester = '20202';COUNT(*) 统计行;COUNT(column) 统计非空值;COUNT(DISTINCT column) 统计不同值
计算数值列的总和与平均值
寻找一列中的极值
WHERE 在分组前筛选元组,HAVING 在分组后筛选组
01
02
03
04
05SELECT Cno, COUNT(*) AS enrollment_count
FROM SC
WHERE Semester = '20202'
GROUP BY Cno
HAVING COUNT(*) > 10;| 条件位置 | 作用对象 | 例子 |
|---|---|---|
WHERE | 单个元组 | 学期为 20202 |
GROUP BY | 形成分组 | 按课程号分组 |
HAVING | 一个分组 | 人数大于 10 |
结果列来自多个表,连接条件决定哪些元组能够配对
01
02
03
04
05-- Student.Sno = SC.Sno;SC.Cno = Course.Cno
SELECT s.Sno, s.Sname, c.Cname, sc.Grade
FROM Student AS s
JOIN SC AS sc ON s.Sno = sc.Sno
JOIN Course AS c ON sc.Cno = c.Cno;连接形式同时涉及匹配条件、未匹配元组的保留规则和关系拓扑
| 判断维度 | 常见选择 | 先问什么 |
|---|---|---|
| 连接谓词 | 等值、非等值、复合条件 | 哪些元组能够配对? |
| 保留规则 | 内连接、左/右外连接 | 未匹配元组是否保留? |
| 关系拓扑 | 两表、多表、自身连接 | 需要几个关系副本? |
连接判断包括匹配条件、未匹配元组的保留规则和关系拓扑。FULL OUTER JOIN 属于标准 SQL,MySQL 8.4 没有直接语法;MySQL 8.4 可直接使用左/右外连接
左外连接可以列出 Student 中所有学生,包括尚未选课的学生
01
02
03SELECT s.Sno, s.Sname, sc.Cno, sc.Grade
FROM Student AS s
LEFT OUTER JOIN SC AS sc ON s.Sno = sc.Sno;NULL 补位;WHERE 再筛选右表列,可能把这些主体行排除| 结果部分 | 内连接 | 左外连接 |
|---|---|---|
| 已选课学生 | 保留 | 保留 |
| 未选课学生 | 舍弃 | 保留并补空值 |
| 业务含义 | 只看匹配记录 | 以左表为完整主体 |
外层查询把内层查询返回的集合用于条件判断;本例是不相关子查询
01
02
03
04
05
06SELECT Sno, Sname
FROM Student
WHERE Smajor IN
(SELECT Smajor
FROM Student
WHERE Sname = '刘晨');子查询结果若为单值,可用 = 或 > 比较;若为集合,可用 IN、ANY 或 ALL;若只判断是否存在,可用 EXISTS 或 NOT EXISTS
01
02
03
04
05
06
07
08
09-- EXISTS:只判断是否有匹配行
SELECT s.Sname
FROM Student AS s
WHERE EXISTS (
SELECT 1
FROM SC AS sc
WHERE sc.Sno = s.Sno
AND sc.Cno = '81001'
);先标出父查询列,再判断每一行对应的内层结果
01
02
03
04
05
06SELECT x.Sno, x.Cno
FROM SC x
WHERE x.Grade >=
(SELECT AVG(y.Grade)
FROM SC y
WHERE y.Sno = x.Sno);y.Sno = x.Sno 是相关条件:x.Sno 来自父查询,y.Sno 来自内层查询。Grade 为 NULL 时的比较留到 3.5。相同问题也可以用连接、聚集或派生表表达,应先验证结果是否正确,再比较写法
先检查列数、对应列类型、列顺序与业务含义,再决定并、交或差
01
02
03
04
05
06
07SELECT Sno
FROM SC
WHERE Cno = '81001'
UNION
SELECT Sno
FROM SC
WHERE Cno = '81002';| 运算 | 结果 | 业务提问 |
|---|---|---|
UNION | 两个结果的并集 | 满足任一条件 |
INTERSECT | 两个结果的交集 | 同时满足两个条件 |
EXCEPT | 左结果减去右结果 | 满足左条件且排除右条件 |
不加 ALL 的集合运算默认按集合语义去重;UNION ALL 明确保留重复行。UNION、INTERSECT、EXCEPT 属于标准 SQL,MySQL 对这些运算的支持范围需要按授课时版本核对
派生表让主查询继续处理一个已经整理过的中间关系
01
02
03
04
05
06
07SELECT SC.Sno, SC.Cno
FROM SC
JOIN (SELECT Sno, AVG(Grade) AS Avg_grade
FROM SC
GROUP BY Sno) AS Avg_SC
ON SC.Sno = Avg_SC.Sno
WHERE SC.Grade >= Avg_SC.Avg_grade;派生表必须有别名,例如 Avg_SC(Sno, Avg_grade);它只在当前查询中有效,不作为持久化对象保存,也不是视图
SQL 描述结果条件,数据库管理系统(DBMS)再选择具体访问方式
01
02
03
04EXPLAIN
SELECT s.Sname, c.Cname, sc.Grade
FROM Student s JOIN SC sc ON s.Sno = sc.Sno
JOIN Course c ON sc.Cno = c.Cno;用户先写结果语义,DBMS 再选择执行计划;具体产品决定语法与边界,EXPLAIN 可以观察当前产品的执行路径
查询先确定输入关系,再筛选元组、形成结果列,并按需组合中间结果
单表查询决定目标列、行条件、去重、排序、聚集和分组
多表查询用连接条件和别名组合关系,并明确外连接的保留规则
嵌套、集合和派生表可以表达复杂条件;它们产生的中间结果在形状和作用域上不同
SQL 写法应先满足结果关系,再比较可读性和产品边界
SELECT、DISTINCT、WHERE、GROUP BY 与 HAVING 分别处理什么?WHERE 与 HAVING 的先后如何?NULL 表示什么?=、IN、EXISTS?y.Sno = x.Sno 为什么表示相关?EXPLAIN 观察执行计划?