我正在运行以下查询以获得员工表中的第三高薪并且它工作正常,但我无法理解其逻辑.子查询值如何与主查询匹配(左侧部分).有人可以解释一下这个查询背后的逻辑是什么吗?
select e1.salary
from employee as e1
where 3 = (select count(salary)
from employee as e2
where e1.salary<=e2.salary)
Run Code Online (Sandbox Code Playgroud)
PS:我可以理解count()
返回的行数(所有记录都是唯一的).
Mar*_*own 21
这个查询基本上是说:
for each row in employee assign to e1
count = 0
for each row in employee assign to e2
if e1.salary <= e2.salary
count = count + 1
end if
end for
if count = 3
add e1 to result set
end if
end for
return result set
Run Code Online (Sandbox Code Playgroud)
总结对于employee表中的每一行,它第二次访问该表并计算具有较低或相等工资的行数.如果恰好有3,则会将行添加到结果中.
值得指出的是,如果有多个员工具有相同的薪水,这可能会出错.您可能想要的是具有排名功能的查询.像这样的东西:
SELECT salary
FROM
(SELECT
salary
,DENSE_RANK () OVER (ORDER BY salary DESC) [rank]
FROM employee) t
WHERE
[rank] = 3
Run Code Online (Sandbox Code Playgroud)
"第三高峰"究竟是什么意思可能有点含糊不清.如果我们有8,8,6,5的工资,则上述将返回5.如果我们想要6,您需要将DENSE_RANK更改为ROW_NUMBER,如下所示:
SELECT salary
FROM
(SELECT
salary
,ROW_NUMBER () OVER (ORDER BY salary DESC) [rank]
FROM employee) t
WHERE
[rank] = 3
Run Code Online (Sandbox Code Playgroud)
如果第三位有一个平局,上面的DENSE_RANK版本也会遇到返回多行的问题.这是否可取取决于究竟需要什么,但可以通过使用工资的汇总函数来减少这种情况.
SELECT MAX(salary)
FROM
(SELECT
salary
,DENSE_RANK() OVER (ORDER BY salary desc) [rank]
FROM employee) t
WHERE
[rank] = 3
Run Code Online (Sandbox Code Playgroud)
考虑这些值:
Salary:
1
2
3
4
5
6
7
8
e1 e2
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
Run Code Online (Sandbox Code Playgroud)
因为e1.1
有8行e2
大于或等于e1.1
.
因为e1.2
有7行e2
大于或等于e1.2
.
...
因为e1.6
有3行e2
大于或等于e1.6
.
这是一个非常奇怪和令人困惑的选择语句.我只想使用DENSE_RANK
窗口函数重写它,因为如果你有几行具有相同的工资,你将得不到正确的结果:
DECLARE @t TABLE ( i INT )
INSERT INTO @t
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 ),
( 5 ),
( 6 ),
( 8 ),
( 8 );
WITH cte
AS ( SELECT * ,
DENSE_RANK() OVER ( ORDER BY i DESC ) AS rn
FROM @t
)
SELECT *
FROM cte
WHERE rn = 3
Run Code Online (Sandbox Code Playgroud)
结果在5
你的初始选择陈述将导致6
我认为根本不是第三高薪.
employee
表中的每个薪水e1
都会传递给sub-query
.
Sub-query
会发现所有salaries
那些都不及通过salary
并计算它.
对于通过的工资,如果子查询返回计数,3
那么将产生该工资
考虑员工表中有5条记录
1
2
3
4
5
6
7
8
Run Code Online (Sandbox Code Playgroud)
当1
从传递e1
,子查询会像
select e1.salary
from employee as e1
where 3 = (select count(salary)
from employee as e2
where 1<=e2.salary)
Run Code Online (Sandbox Code Playgroud)
现在子查询中的计数将为8,因为所有记录都大于或等于1.计数不等于3因此salary 1
不会返回
当2
从e1传递时,子查询将是
select e1.salary
from employee as e1
where 3 = (select count(salary)
from employee as e2
where 2<=e2.salary)
Run Code Online (Sandbox Code Playgroud)
现在子查询中的计数将为7,因为除了1以外所有记录都大于或等于2.计数不等于3因此Salary 2
不会返回
当6
从e1传递时,子查询将是
select e1.salary
from employee as e1
where 3 = (select count(salary)
from employee as e2
where 6<=e2.salary)
Run Code Online (Sandbox Code Playgroud)
现在有三个记录大于或等于6(即)6,7,8因此计数将为3且条件满足.所以salary 6
将被退回