SQL示例:为什么薪资表需要关联多次
本文解释了SQL查询中为何需要两次关联薪资表来比较员工和经理的薪资。
核心原因是:一次JOIN只能获取一个人的薪资信息,而查询需要同时获取员工和经理(两个不同个体)的当前薪资进行对比。
通过分步示例说明:第一次关联获取员工薪资,第二次关联获取经理薪资。
文章还指出,若需比较更多角色(如员工、经理、总监),则需相应增加关联次数(如三次)。
这种设计是因为关系型数据库中,JOIN操作基于值匹配,不同角色的薪资需通过独立查询条件获取。
SQL示例:为什么薪资表需要关联两次
题目描述
有一个,部门关系表dept_emp简况如下:
| emp_no | dept_no | from_date | to_date |
| 10001 | d001 | 1986-06-26 | 9999-01-01 |
| 10002 | d001 | 1996-08-03 | 9999-01-01 |
有一个部门经理表dept_manager简况如下:
| dept_no | emp_no | from_date | to_date |
| d001 | 10002 | 1996-08-03 | 9999-01-01 |
有一个薪水表salaries简况如下:
| emp_no | salary | from_date | to_date |
| 10001 | 88958 | 2002-06-22 | 9999-01-01 |
| 10002 | 72527 | 1996-08-03 | 9999-01-01 |
获取员工其当前的薪水比其manager当前薪水还高的相关信息,
第一列给出员工的emp_no,
第二列给出其manager的manager_no,
第三列给出该员工当前的薪水emp_salary,
第四列给该员工对应的manager当前的薪水manager_salary
select d1.emp_no, d2.emp_no as manager_no, d3.salary as emp_salary, d4.salary as manager_salary from dept_emp d1 join dept_manager d2 on d1.dept_no =d2.dept_no join salaries d3 on d1.emp_no=d3.emp_no join salaries d4 on d2.emp_no=d4.emp_no where d3.salary > d4.salary;薪资表需要关联两次,是因为我们要获取两种不同角色的当前薪资:
核心原因
一次关联只能获取一个人的薪资信息,但我们需要:
员工的薪资(来自
salaries表)经理的薪资(也来自
salaries表)
这两个人不同,所以必须分别关联。
分步理解
第一次关联 salaries (d3)
sql
JOIN salaries d3 ON d1.emp_no = d3.emp_no
d1.emp_no是员工编号(如 10001)关联后,
d3.salary取出的是这个员工自己的薪水
第二次关联 salaries (d4)
sql
JOIN salaries d4 ON d2.emp_no = d4.emp_no
d2.emp_no是经理编号(如 10002)关联后,
d4.salary取出的是这个经理的薪水
直观示例
假设当前已经关联了部门信息(中间结果):
| d1.emp_no (员工) | d2.emp_no (经理) |
|---|---|
| 10001 | 10002 |
现在需要补充薪资:
第一次 JOIN salaries (d3):拿 10001 的薪资 → 88958
第二次 JOIN salaries (d4):拿 10002 的薪资 → 72527
如果只关联一次,要么只能拿到员工薪资,要么只能拿到经理薪资,无法同时获得两者进行比较。
类比理解
就像你要比较两个人的身高:
需要查第一个人的身高记录
也需要查第二个人的身高记录
即使数据存在同一张「身高表」里,也要查两次,因为查询条件不同(一次查 A,一次查 B)
其他写法(了解即可)
理论上也可以把salaries分别起别名,写成子查询,但本质还是两次访问:
sql
SELECT d1.emp_no, d2.emp_no AS manager_no, (SELECT salary FROM salaries WHERE emp_no = d1.emp_no AND to_date = '9999-01-01') AS emp_salary, (SELECT salary FROM salaries WHERE emp_no = d2.emp_no AND to_date = '9999-01-01') AS manager_salary FROM dept_emp d1 JOIN dept_manager d2 ON d1.dept_no = d2.dept_no WHERE ...;
但两次 JOIN 的方式更清晰、性能通常更好。
总结
| 需要的数据 | 来自哪条记录 | 关联条件 |
|---|---|---|
| 员工薪资 | salaries 表,对应 emp_no = 员工编号 | d1.emp_no = d3.emp_no |
| 经理薪资 | salaries 表,对应 emp_no = 经理编号 | d2.emp_no = d4.emp_no |
每人一条薪资记录 → 需要两次独立的 JOIN✅
还是不理解为什么要关联两次薪资表,领导也在员工表中,第一次员工表关联薪资表,不就可以查出领导的薪资吗
你说得非常对!这个问题的核心就在这里,让我详细解释为什么不能一次查出。
你的理解误区
你说"领导也在员工表中",这是正确的。但问题在于:
一次关联查询,只能为一"条"记录获取薪资
具体例子说明
假设我们已经关联了部门和经理关系(中间结果):
text
dept_emp (普通员工) dept_manager (经理) emp_no | dept_no dept_no | emp_no (经理) 10001 | d001 d001 | 10002
这时,一条查询结果记录包含:
员工编号:10001
经理编号:10002
现在要取薪资:
如果你只关联一次 salaries 表
sql
JOIN salaries s ON ???.emp_no = s.emp_no
这个ON条件只能选一个:
如果 ON
de.emp_no = s.emp_no→ 能拿到员工薪资(10001的薪资),拿不到经理薪资如果 ON
dm.emp_no = s.emp_no→ 能拿到经理薪资(10002的薪资),拿不到员工薪资
无法同时满足"一条记录里既有员工薪资,又有经理薪资"
为什么不能用子查询或窗口函数?
你可能觉得:既然领导在员工表里,那用子查询不行吗?
sql
SELECT de.emp_no, dm.emp_no AS manager_no, s1.salary AS emp_salary, (SELECT salary FROM salaries s2 WHERE s2.emp_no = dm.emp_no ...) AS manager_salary FROM ...
这样写本质还是两次访问 salaries 表,只不过第二次访问写成了子查询。
换个角度理解:关系型数据库的"行"概念
每张表关联一次,是在给当前结果集的每一行新增列。
初始结果集(未关联薪资前):
| 员工编号 | 经理编号 |
|---|---|
| 10001 | 10002 |
| 10003 | 10004 |
要变成最终结果:
| 员工编号 | 经理编号 | 员工薪资 | 经理薪资 |
|---|---|---|---|
| 10001 | 10002 | 88958 | 72527 |
| 10003 | 10004 | ? | ? |
你需要:
根据"员工编号"这一列去 salaries 表查薪资 → 得到"员工薪资"列
根据"经理编号"这一列去 salaries 表查薪资 → 得到"经理薪资"列
这必然需要两次独立的查找操作。
类比理解
想象你有两张表:
人员表:姓名、性别
收入表:姓名、工资
现在要查:张三(员工)和他的领导李四(也在人员表中)的工资对比
一次查询结果需要包含:
| 员工姓名 | 员工工资 | 领导姓名 | 领导工资 |
|---|---|---|---|
| 张三 | 8000 | 李四 | 15000 |
你要去"收入表"查两次:
查"张三"的工资 → 8000
查"李四"的工资 → 15000
虽然张三和李四都在同一张人员表,但他们是不同的记录,必须分别查收入表。
什么时候可以关联一次?
只有当你要获取的薪资来自同一个人时:
sql
-- 查询员工及其自己的薪资(只需要关联一次) SELECT de.emp_no, s.salary FROM dept_emp de JOIN salaries s ON de.emp_no = s.emp_no
但你要比较的是员工 vs 领导(两个人),所以必须关联两次。
总结
| 你的想法 | 实际情况 |
|---|---|
| "领导也在员工表中" | ✅ 正确 |
| "所以一次关联就能拿到领导薪资" | ❌ 错误 |
根本原因:
一次 JOIN 是根据当前结果集中的某一个人去查薪资
你的结果集中,一行记录包含两个人(员工和领导)
因此必须分别为这两个人各 JOIN 一次 salaries 表
这就是为什么需要两次关联薪资表!
你的结果集中,一行记录包含两个人(员工和领导)?是两个人还是两类人,如果有第三个人要查薪资,难道还需关联第三次薪资表吗
非常精准的问题!让我用具体例子说明:
先回答你的问题
"一行记录包含两个人"是指两个不同的个体,不是"两类人"。
如果一行记录需要显示3个人的薪资,确实需要关联第3次薪资表!
具体例子:一行为什么会有两个人?
看这条SQL产生的中间结果(关联部门关系后,还没关联薪资):
sql
SELECT de.emp_no, dm.emp_no AS manager_no FROM dept_emp de JOIN dept_manager dm ON de.dept_no = dm.dept_no
结果集(未关联薪资前):
| 员工编号 | 经理编号 | |
|---|---|---|
| 10001 | 10002 | |
| 10003 | 10002 | (假设同一个部门有多个员工) |
| 10004 | 10005 |
每一行包含了两个人:
第1列:员工(一个人)
第2列:经理(另一个人)
虽然经理也是员工,但在这一行记录里,他们是两个不同的具体的人。
如果要查第三个人的薪资
假设需求变成:员工、经理、总监三者的薪资对比
表结构:
dept_emp:员工dept_manager:经理dept_director:总监
sql
WITH current_salary AS ( SELECT emp_no, salary FROM salaries WHERE to_date = '9999-01-01' ) SELECT de.emp_no, dm.emp_no AS manager_no, dd.emp_no AS director_no, s1.salary AS emp_salary, s2.salary AS manager_salary, s3.salary AS director_salary -- 第三个人的薪资 FROM dept_emp de JOIN dept_manager dm ON de.dept_no = dm.dept_no JOIN dept_director dd ON de.dept_no = dd.dept_no JOIN current_salary s1 ON de.emp_no = s1.emp_no -- 关联第1次:员工 JOIN current_salary s2 ON dm.emp_no = s2.emp_no -- 关联第2次:经理 JOIN current_salary s3 ON dd.emp_no = s3.emp_no; -- 关联第3次:总监
确实需要关联3次薪资表,因为一行结果集包含了3个不同的人。
核心规律
结果集中,有几个"角色"需要显示薪资,就需要关联几次薪资表
| 需求 | 结果集一行包含 | 关联薪资表次数 |
|---|---|---|
| 员工自己 | 1个人 | 1次 |
| 员工 vs 经理 | 2个人 | 2次 |
| 员工 vs 经理 vs 总监 | 3个人 | 3次 |
| 员工 vs 他的5个上级 | 6个人 | 6次 |
为什么容易混淆?
你可能会想:"经理也是员工,为什么不能一次查出?"
因为SQL的JOIN是基于值匹配,不是基于"角色":
第一次JOIN:用"员工编号"去匹配 → 拿到员工薪资
第二次JOIN:用"经理编号"去匹配 → 拿到经理薪资
即使是同一张表,只要查询条件不同(不同的emp_no),就需要分别JOIN。
总结
| 你的理解 | 正确理解 |
|---|---|
| "一行记录包含两类人" | ❌ 是两个具体的人 |
| "经理也在员工表,应该一次查出" | ❌ 不同的人需要不同的查询条件 |
| "有第三个人就需要第三次关联" | ✅完全正确 |
这就是为什么你的原SQL需要两次关联salaries表——因为一行结果集里,员工和经理是两个不同的具体的人。
