3. 关系数据库标准语言 SQL
3.4 数据查询
### 数据查询
SELECT [ALL | DISTINCT] <目标列表达式>, <目标列表达式>, ...
FROM <表名或视图名> [AS <别名>]
[WHERE <条件表达式>]
[GROUP BY <列名1> [HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC|DESC]];
### 查询过程
- 根据 WHERE 子句中的条件表达式
- 从 FROM 子句指定的表中选出满足条件的元组
- 根据 SELECT 子句中的目标列表达式
- 选取元组中的属性
- 形成结果表
### 查询子句
- GROUP BY子句按照指定的列进行分组
- 可在每个组上应用聚集函数
- 若有 HAVING 条件则只输出满足条件的组
- 若有 ORDER BY 子句则对结果表排序
### 查询指定列
SELECT Sno, Sname FROM Student;
### 查询全部列
SELECT * FROM Student;
### 查询经过计算的值
SELECT Sname, 2024 - Sage FROM Student;
### 指定列别名
SELECT Sname AS NAME, 2024 - Sage AS BIRTHDAY
FROM Student;
### 消除取值重复的行
SELECT DISTINCT Sno FROM SC;
### 査询满足条件的元组
- 使用 WHERE 子句
- 比较: <, >, <=, >=, =, !=
- 范围: BETWEEN AND, NOT BETWEEN AND
- 集合: IN, NOT IN
### 比较
SELECT Sname
FROM Student
WHERE Sdept = 'CS';
### 范围
SELECT Sname, Sdept, Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
### 集合
SELECT Sname, Ssex
FROM Student
WHERE Sdept IN ('CS', 'MA', 'IS');
### 字符匹配
- 使用 LIKE 进行字符串匹配
- 可以使用通配符
- "%" 代表任意长度的字符串
- "_" 代表任意单个字符
### 字符匹配
SELECT * FROM Student
WHERE Sno LIKE '201215121';
SELECT Sname, Sno, Ssex FROM Student
WHERE Sname LIKE '刘%';
SELECT Sname FROM Student
WHERE Sname LIKE '欧阳_';
SELECT Sname, Sno FROM Student
WHERE Sname LIKE '_阳%';
SELECT Sname, Sno, Ssex FROM Student
WHERE Sname NOT LIKE '刘%';
### 涉及空值的查询
SELECT Sno, Cno FROM SC
WHERE Grade IS NULL;
SELECT Sno, Cno FROM SC
WHERE Grade IS NOT NULL;
- 使用 IS NULL 谓词查询空值
- 使用 IS NOT NULL 谓词查询非空值
### 多重条件查询
SELECT Sname FROM Student
WHERE Sdept = 'CS' AND Sage < 20;
SELECT Sname, Ssex
FROM Student
WHERE Sdept = 'CS' OR Sdept = 'MA' OR Sdept = 'IS';
- 使用逻辑运算符 AND 和 OR 连接多个查询条件
- AND 的优先级高于 OR
- 可以使用括号改变优先级
### ORDER BY子句
SELECT Sno, Grade FROM SC WHERE Cno = '3'
ORDER BY Grade DESC;
SELECT * FROM Student ORDER BY Sdept, Sage DESC;
- 对查询结果按照属性列排序
- 可以对一个或多个属性列排序
- 默认按升序排列
### 聚集函数
- COUNT 函数
- SUM 函数
- AVG 函数
- MAX 函数
- MIN 函数
### COUNT 函数
SELECT COUNT(*) FROM Student;
SELECT COUNT(DISTINCT Sno) FROM SC;
- 用于统计元组个数或某一列中值的个数
- 查询学生总人数
- 查询选修了课程的学生人数
### SUM 函数
SELECT SUM(Grade) FROM SC WHERE Cno = '1';
- 用于计算某一列值的总和 (此列必须是数值型) .
- 计算选修 1 号课程的学生平均成绩
### AVG 函数
SELECT AVG(Grade) FROM SC WHERE Cno = '1';
- 用于计算某一列值的平均值 (此列必须是数值型)
- 计算选修 1 号课程的学生平均成绩
### MAX 函数
SELECT MAX(Grade) FROM SC WHERE Cno = '1';
- 用于求一列值中的最大值
- 查询选修 1 号课程的学生最高分数
### MIN 函数
SELECT MIN(Grade) FROM SC WHERE Cno = '1';
- 用于求一列值中的最小值
- 查询选修1号课程的学生最低分数
### 使用聚集函数的注意事项
- 遇到空值时除 `COUNT(*)` 外都只处理非空值
- `WHERE` 子句中不能使用聚集函数作为条件表达式
- 聚集函数只能用于 `SELECT` 子句和 `GROUP BY` 中的 `HAVING` 子句
### GROUP BY 子句
SELECT Cno, COUNT(Sno) FROM SC GROUP BY Cno;
SELECT Sno FROM SC
GROUP BY Sno
HAVING COUNT(*) > 3;
- 将查询结果按某一列或多列的值分组
- 为了细化聚集函数的作用对象
- 求各个课程号及相应的选课人数
- 查询选修了三门以上课程的学生学号
### WHERE 与 HAVING 的区别
- `WHERE` 子句与 `HAVING` 短语的区别在于作用对象不同
- `WHERE` 子句作用于基本表或视图
- `HAVING` 短语作用于组
### 查询示例
SELECT Sno, AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG(Grade) >= 90;
- 平均成绩大于等于 90 分的学生学号和平均成绩
### 连接查询
- 同时涉及两个以上的表的查询操作
- 等值连接查询
- 自然连接查询
- 非等值连接查询
- 自身连接查询
- 外连接查询
- 复合条件连接查询
### 等值连接查询
- 用于连接两个表的条件称为连接条件
- <表名1>.<列名1><比较运算符><表名2>.<列名2>
- 比较运算符主要有=, >, <, <=, >=, != (或<>) 等
- 连接条件中的列名称为连接字段
- 当连接运算符为 = 时称为等值连接
### 连接查询
SELECT Student.*, SC.*
FROM Student, SC
WHERE Student.Sno = SC.Sno;
- 查询学生及其选修课程
### 自身连接
- 一个表与自身进行连接
### 查询每门课的间接先修课
SELECT FIRST.Cno, SECOND.Cpno
FROM Course FIRST, Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
- 为了得到每门课的间接先修课 (即先修课的先修课), 需要将 Course 表与自身进行连接
- 为 Course 表取别名为 FIRST 和 SECOND
### 嵌套查询
SELECT Sname
FROM Student
WHERE Sno IN
(SELECT Sno
FROM SC
WHERE Cno='2');
- 一个 `SELECT-FROM-WHERE` 语句是一个查询块
- 查询块可以嵌套
### 嵌套查询
- 上层的査询块称为外层查询或父查询
- 下层查询块称为内层查询或子查询
- SQL 语言允许多层嵌套査询
- 子査询的 `SELECT` 语句不能用 `ORDER BY` 子句
### 带 IN 的子查询
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname='刘晨');
- 子查询的结果往往是一个集合
- `IN` 在嵌套査询中最常使用
### 相关与不相关子查询
- 查询条件是否依赖于父查询
### 带比较运算符的子查询
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept =
(SELECT Sdept
FROM Student
WHERE Sname='刘晨');
- 内层查询返回单个值时
- 可以用比较运算符
### 带 ANY 或 ALL 的子查询
- 返回多值时要用 ANY 或 ALL 修饰符
- 必须同时使用比较运算符
- > ANY 大于子查询结果中的某个值 MIN
- > ALL 大于子查询结果中的所有值 MAX
- < ANY 小于子査询结果中的某个值 MAX
- < ALL 小于子查询结果中的所有值 MIN
- >= ANY 大于等于子查询结果中的某个值 MIN
- >= ALL 大于等于子査询结果中的所有值 MAX
- <= ANY 小于等于子査询结果中的某个值 MAX
- <= ALL 小于等于子查询结果中的所有值 MIN
- = ANY 等于子查询结果中的某值 IN
- = ALL 等于子查询结果中的所有值 (无意义)
- != ANY 不等于子査询结果中的某个值 (无意义)
- != ALL 不等于子査询结果中的任何一个值 NOT IN
### 集合查询
- 査询结果是元组集合
- 多个 `SELECT` 语句的结果可集合操作
- 并操作 `UNION`
- 交操作 `INTERSECT`
- 差操作 `EXCEPT`
- 各查询结果的列数必须相同
- 对应项的数据类型也必须相同
### 例 64
SELECT *
FROM Student
WHERE Sdept = 'CS'
UNION
SELECT *
FROM Student
WHERE Sage <= 19;
- `UNION` 合并多个查询结果时会自动去重
### 例 66
SELECT *
FROM Student
WHERE Sdept = 'CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage <= 19;
### 例 68
SELECT *
FROM Student
WHERE Sdept = 'CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage <= 19;
### 基于派生表的查询
SELECT Sno, Cno
FROM SC, (SELECT Sno, Avg(Grade)
FROM SC GROUP BY Sno)
AS Avg_sc(avg_sno,avg_grade)
WHERE SC.Sno = Avg_sc.avg_sno
and SC.Grade >= Avg_sc.avg_grade
- 子查询可以出现在 `FROM` 子句中
- 子查询生成临时派生表
### SELECT 语句
SELECT [ALL | DISTINCT] <目标列表达式> [别名]
[, <目标列表达式> [别名] ]...
FROM <表名或视图名> [别名]
[, <表名或视图名> [别名] ] ... |
( <SELECT语句> ) [AS] <别名>
[WHERE <条件表达式> ]
[GROUP BY <列名 1> [HAVING <条件表达式> ] ]
[ORDER BY <列名 2> [ASC|DESC] ];
### 目标列表达式的可选格式
- *
- <表名>.*
- COUNT( [DISTINCT | ALL] *)
- [ <表名> .] <属性列名表达式> [, [ <表名> .] <属性列名表达式> ] ...
### 聚集函数的一般格式
- COUNT
- SUM
- AVG
- MAX
- MIN
- 后接 ( [DISTINCT | ALL] <列名> )
### WHERE 子句的条件表达式
- 比较运算符θ
- BETWEEN
- IN
- LIKE
- IS NULL
- EXISTS
- 条件表达式 1 [AND | OR] 条件表达式 2

### 3.4 数据查询
- 在 SQL 中, 如何使用 SELECT 语句检索数据?
- 如何使用 WHERE 子句过滤 SELECT 语句的结果?
- 如何使用 ORDER BY 子句对查询结果进行排序?
- 在 SQL 中,常见的聚合函数有哪些?
- 如何使用 GROUP BY 子句分组操作?
----
[ 3.3 数据定义](dbds-3-3.html#/overview)
[| 练习 |](dbds-exec.html)
[ 3.5 数据更新](dbds-3-5.html#/overview)