答案总览
这套答案与前面两份知识点学习页保持同一主题线:先区分 单值 / 多值 / 相关子查询 / EXISTS,再区分 UNION 与连接查询。若学生出现共性问题,通常集中在以下三个点:子查询方向写反、UNION 两边列结构不一致、把 UNION 和 JOIN 混淆。
参考答案
1
单值子查询:比赵琳琳年龄大的学生
SELECT sno, sn, age
FROM s
WHERE age > (
SELECT age
FROM s
WHERE sn = '赵琳琳'
)
ORDER BY age, sno;
运行结果
| sno | sn | age |
|---|---|---|
| s3 | 王敏 | 20 |
| s4 | 陈晨 | 21 |
| s6 | 周楠 | 22 |
解析:子查询先查出赵琳琳的年龄 19,外层再筛选 age > 19 的学生。
2
多值子查询:查询 s2 选修的课程信息
SELECT cno, cn, ct
FROM c
WHERE cno IN (
SELECT cno
FROM sc
WHERE sno = 's2'
)
ORDER BY cno;
运行结果
| cno | cn | ct |
|---|---|---|
| c1 | 程序设计基础 | 64 |
| c2 | 数据库原理 | 48 |
解析:sc 表先返回 s2 的课程号集合 {c1, c2},外层再到 c 表中取出这两门课的完整信息。
3
多值子查询:比计算机专业所有教师工资都高
SELECT tno, tn, maj, sal
FROM t
WHERE sal > ALL (
SELECT sal
FROM t
WHERE maj = '计算机'
)
AND maj <> '计算机';
补充:
等价写法:
SELECT tno, tn, maj, sal
FROM t
WHERE sal > (
SELECT MAX(sal)
FROM t
WHERE maj = '计算机'
)
AND maj <> '计算机';运行结果
| tno | tn | maj | sal |
|---|---|---|---|
| t4 | 刘芳 | 英语 | 7000 |
解析:计算机专业教师工资为 5200、6800、6100。要比“所有人都高”,本质上就是要大于最大值 6800。
4
相关子查询:查询选修 c1 的学生
SELECT sno, sn
FROM s
WHERE 'c1' IN (
SELECT cno
FROM sc
WHERE sno = s.sno
)
ORDER BY sno;
运行结果
| sno | sn |
|---|---|
| s1 | 张三 |
| s2 | 赵琳琳 |
| s3 | 王敏 |
| s6 | 周楠 |
解析:这是相关子查询。外层每取到一个学生,内层就会查询“这个学生选了哪些课”,再判断其中是否包含 c1。
5
NOT EXISTS:查询没有选修 c1 的学生
SELECT sno, sn
FROM s
WHERE NOT EXISTS (
SELECT *
FROM sc
WHERE sno = s.sno AND cno = 'c1'
)
ORDER BY sno;
运行结果
| sno | sn |
|---|---|
| s4 | 陈晨 |
| s5 | 李雪 |
解析:NOT EXISTS 的含义是:找不到“该学生选了 c1”这条记录。满足条件的只有 s4 和 s5。
6
EXISTS:查询 t1 教授的课程信息
SELECT cno, cn, ct
FROM c
WHERE EXISTS (
SELECT *
FROM tc
WHERE cno = c.cno AND tno = 't1'
)
ORDER BY cno;
运行结果
| cno | cn | ct |
|---|---|---|
| c1 | 程序设计基础 | 64 |
| c2 | 数据库原理 | 48 |
解析:外层从课程表 c 逐行判断,只要 tc 表中存在“当前课程由 t1 讲授”的记录,这门课就会被保留。
7
UNION:合并两个专业的学生信息
SELECT sno, sn, maj
FROM s
WHERE maj = '计算机'
UNION
SELECT sno, sn, maj
FROM s
WHERE maj = '数学';
运行结果
| sno | sn | maj |
|---|---|---|
| s1 | 张三 | 计算机 |
| s2 | 赵琳琳 | 数学 |
| s3 | 王敏 | 计算机 |
| s5 | 李雪 | 数学 |
| s6 | 周楠 | 计算机 |
解析:两边都来自学生表,且都返回 3 列,结构一致,所以可以直接用 UNION 纵向合并。
8
UNION:合并两门课程的统计结果
SELECT cno AS 课程号,
SUM(score) AS 总分,
AVG(score) AS 平均分
FROM sc
WHERE cno = 'c1'
GROUP BY cno
UNION
SELECT cno AS 课程号,
SUM(score) AS 总分,
AVG(score) AS 平均分
FROM sc
WHERE cno = 'c2'
GROUP BY cno;
运行结果
| 课程号 | 总分 | 平均分 |
|---|---|---|
| c1 | 348 | 87.00 |
| c2 | 335 | 83.75 |
解析:c1 的成绩为 86、88、79、95,总分 348,平均分 87。c2 的成绩为 90、92、69、84,总分 335,平均分 83.75。
9
UNION 去重观察题
SELECT sno, sn
FROM s
WHERE maj = '计算机'
UNION
SELECT sno, sn
FROM s
WHERE age >= 20
ORDER BY sno;
运行结果
| sno | sn |
|---|---|
| s1 | 张三 |
| s3 | 王敏 |
| s4 | 陈晨 |
| s6 | 周楠 |
解析:s3 和 s6 同时满足“计算机专业”和“年龄 >= 20”,但在 UNION 结果中各只保留一行,这正好说明 UNION 会自动去重。
10
综合题:子查询 + UNION
SELECT sno, sn, maj
FROM s
WHERE NOT EXISTS (
SELECT *
FROM sc
WHERE sno = s.sno AND cno = 'c1'
)
UNION
SELECT sno, sn, maj
FROM s
WHERE maj = '英语'
ORDER BY sno;
运行结果
| sno | sn | maj |
|---|---|---|
| s4 | 陈晨 | 英语 |
| s5 | 李雪 | 数学 |
解析:前半部分得到没有选 c1 的学生 s4、s5;后半部分得到英语专业学生 s4。两部分用 UNION 合并后,重复的 s4 只保留一次。