多表查询案例
12 道多表查询综合练习(连接查询 + 子查询),示例数据沿用 多表查询 的
emp/dept表。
补充:薪资等级表 salgrade
CREATE TABLE salgrade(
grade INT, -- 等级
losal INT, -- 最低薪资
hisal INT -- 最高薪资
) COMMENT '薪资等级表';
INSERT INTO salgrade VALUES
(1, 0, 3000), (2, 3001, 5000), (3, 5001, 8000), (4, 8001, 10000),
(5, 10001, 15000), (6, 15001, 20000), (7, 20001, 25000), (8, 25001, 30000);
薪资落在
[losal, hisal]区间内,用BETWEEN ... AND ...关联等级表。
一、练习题
- 查询员工的姓名、年龄、职位、部门信息。
- 查询年龄小于 30 岁的员工姓名、年龄、职位、部门信息。
- 查询拥有员工的部门 ID、部门名称。
- 查询所有年龄大于 40 岁的员工,及其归属的部门名称;如果员工没有分配部门,也需要展示出来。
- 查询所有员工的工资等级。
- 查询"研发部"所有员工的信息及工资等级。
- 查询"研发部"员工的平均工资。
- 查询工资比"灭绝"高的员工信息。
- 查询比平均薪资高的员工信息。
- 查询低于本部门平均工资的员工信息。
- 查询所有的部门信息,并统计部门的员工人数。
- 查询所有学生的选课情况,展示出学生名称、学号、课程名称。
二、参考答案
-- 1. 员工 + 部门(隐式内连接)
SELECT e.name, e.age, e.job, d.name FROM emp e, dept d WHERE e.dept_id = d.id;
-- 2. 年龄小于 30 岁的员工 + 部门(显式内连接)
SELECT e.name, e.age, e.job, d.name FROM emp e INNER JOIN dept d ON e.dept_id = d.id WHERE e.age < 30;
-- 3. 有员工的部门(DISTINCT 去重)
SELECT DISTINCT d.id, d.name FROM dept d JOIN emp e ON d.id = e.dept_id;
-- 4. 年龄大于 40 的员工 + 部门,没有部门的也要展示(左外连接)
SELECT e.*, d.name FROM emp e LEFT JOIN dept d ON e.dept_id = d.id WHERE e.age > 40;
-- 5. 所有员工的工资等级
SELECT e.*, s.grade FROM emp e LEFT JOIN salgrade s ON e.salary BETWEEN s.losal AND s.hisal;
-- 6. 研发部员工的信息及工资等级
SELECT e.*, s.grade FROM emp e
LEFT JOIN salgrade s ON e.salary BETWEEN s.losal AND s.hisal
WHERE e.dept_id = (SELECT id FROM dept WHERE name = '研发部');
-- 7. 研发部员工的平均工资
SELECT AVG(e.salary) FROM emp e
WHERE e.dept_id = (SELECT id FROM dept WHERE name = '研发部');
-- 8. 工资比"灭绝"高的员工(标量子查询)
SELECT * FROM emp WHERE salary > (SELECT salary FROM emp WHERE name = '灭绝');
-- 9. 工资高于全公司平均工资的员工
SELECT * FROM emp WHERE salary > (SELECT AVG(salary) FROM emp);
-- 10. 低于本部门平均工资的员工(相关子查询:内外层用同一个 dept_id)
SELECT * FROM emp e1
WHERE e1.salary < (SELECT AVG(e2.salary) FROM emp e2 WHERE e2.dept_id = e1.dept_id);
-- 11. 所有部门及其员工人数(SELECT 之后的子查询)
SELECT d.*, (SELECT COUNT(*) FROM emp WHERE dept_id = d.id) '人数' FROM dept d;
-- 12. 学生选课情况(三表联查:学生、中间表、课程)
SELECT s.name, s.no, c.name FROM student s, student_course sc, course c
WHERE s.id = sc.studentid AND sc.courseid = c.id;
三、要记住的套路
| 需求特征 | 做法 |
|---|---|
| 只要两表都匹配的数据 | 内连接(隐式 / 显式) |
| 主表数据全部保留 | 左外 / 右外连接(LEFT JOIN + IS NULL 也能找「没有关联数据」的行) |
| 查同一张表的层级关系(员工-领导) | 自连接 + 表别名 |
| 过滤条件是一个值 | 标量子查询(= / > 等) |
| 过滤条件是一列 | 列子查询(IN / ANY / ALL) |
| 过滤条件是一行多列 | 行子查询((字段1, 字段2) = (SELECT ...)) |
| 子查询结果当表用 | 表子查询放在 FROM 之后并起别名 |
| 与本部门 / 本行数据比较 | 相关子查询(内外层用同名字段关联) |
相关
- 多表查询(连接查询):示例数据与连接语法
- 子查询:四类子查询
- 多表关系:一对多 / 多对多 / 一对一