这个查询背后的逻辑工作是什么?

时间:2017-01-09 11:07:45

标签: sql sql-server

我正在运行以下查询以获得员工表中的第三高薪并且它工作正常,但我无法理解其逻辑。子查询值如何与主查询匹配(左侧部分)。有人可以解释一下这个查询背后的逻辑是什么吗?

select e1.salary 
from employee as e1 
where 3 = (select count(salary) 
           from employee as e2 
           where e1.salary<=e2.salary)

PS:我可以理解count()返回行数(所有记录都是唯一的)。

4 个答案:

答案 0 :(得分: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

总结对于employee表中的每一行,它第二次访问该表并计算具有较低或相等工资的行数。如果恰好有3,则会将行添加到结果中。

值得指出的是,如果有多个员工的薪水相同,这可能会出错。您可能想要的是具有排名功能的查询。像这样:

SELECT salary
FROM
    (SELECT 
        salary
        ,DENSE_RANK () OVER (ORDER BY salary DESC) [rank]
    FROM employee) t
WHERE
    [rank] = 3

&#34;第三高的&#34;究竟是什么意思?也许有点含糊不清。如果我们有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

如果第三名出现并列,则上面的DENSE_RANK版本也会遇到多行返回的问题。这是否可取取决于究竟需要什么,但可以通过使用工资的汇总函数来减少这一点。

SELECT MAX(salary)
FROM
    (SELECT 
        salary
        ,DENSE_RANK() OVER (ORDER BY salary desc) [rank]
    FROM employee) t
WHERE
    [rank] = 3

答案 1 :(得分:6)

考虑以下这些值:

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

对于e1.1e2中有8行大于或等于e1.1

对于e1.2e2中有7行大于或等于e1.2

...

对于e1.6e2中有3行大于或等于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

5的结果,而您的初始选择语句将导致6我认为根本不是第三高薪。

答案 2 :(得分:5)

employeee1中的每个薪水都会传递给sub-querySub-query会发现所有salaries小于传递的salary并计算它。

如果子查询返回计数为3,则传递的工资将导致该工资

考虑员工表中有5条记录

1
2
3
4
5
6
7
8

1传递e1时,子查询将类似于

select e1.salary 
from employee as e1 
where 3 = (select count(salary) 
           from employee as e2 
           where 1<=e2.salary)

现在子查询中的计数将为8,因为所有记录都大于或等于1.计数不等于3,因此不会返回salary 1

从e1传递2时,子查询将类似于

select e1.salary 
from employee as e1 
where 3 = (select count(salary) 
           from employee as e2 
           where 2<=e2.salary)

现在子查询中的计数将为7,因为除了1之外所有记录都大于或等于2.计数不等于3所以Salary 2它不会被返回

从e1传递6时,子查询将类似于

select e1.salary 
from employee as e1 
where 3 = (select count(salary) 
           from employee as e2 
           where 6<=e2.salary)

现在有三个记录大于或等于6(即)6,7,8所以计数将为3且条件满足。因此将返回salary 6

答案 3 :(得分:1)

事实上它非常简单。第二个查询选择当前(选定)员工(e1)工资较低的所有员工。然后我们说薪水较低或相等的员工数量需要为3.这导致获得第三高工资。