如何在SQL中找到第n个最高薪水?

thi*_*305 6 mysql join sql-server

我找到了一个查询,可以从 Employee 表中找到第 n 个最高工资,但我不明白 (N-1) 的逻辑?

EmpID         Salary
1             90000
2             80000
3             54000
4             37000
5             12000
6             69000
7             50000

SELECT * FROM Employee E1
WHERE (N-1) = (
                SELECT COUNT(DISTINCT(E2.Salary))
                FROM Employee E2
                WHERE E2.Salary > E1.Salary
              )
Run Code Online (Sandbox Code Playgroud)

如果 N=4,那么查询是如何工作的?我是一个完整的 SQL 初学者,请帮忙!

Aar*_*and 18

这里发生的事情是子查询查看每个人的薪水并基本上对它们进行排名,然后将这些薪水与外部薪水进行比较(针对同一个表的单独查询)。所以在这种情况下,如果你说 N = 4 它是说:

WHERE 3 = (number of salaries > outer salary)
Run Code Online (Sandbox Code Playgroud)

因此,查看您拥有的数据,让我们按顺序排列它们并进行比较。

EmpID   Salary   How many *distinct* salaries are greater than this one?
-----   ------   -------------------------------------------------------
5       12000    6
4       37000    5
7       50000    4
3       54000    3
6       69000    2
2       80000    1
1       90000    0
Run Code Online (Sandbox Code Playgroud)

因此,当 n = 4 时,将返回的行是 EmpID 3 (54000)。

在我看来,编写此查询的一种更直观的方法是使用窗口函数,例如RANK(),ROW_NUMBER()DENSE_RANK()(取决于您是否想要联系)。让我们来看看这些不同的函数如何对您的数据起作用(我添加了第 8 行来表示第 4 名的平局):

DECLARE @salary TABLE(EmpID INT, Salary INT);

INSERT @salary VALUES
(1,90000),(2,80000),(3,54000),(4,37000),
(5,12000),(6,69000),(7,50000),(8,54000);

;WITH x AS
(
  SELECT EmpID, Salary, 
    r  = RANK()       OVER (ORDER BY Salary),
    dr = DENSE_RANK() OVER (ORDER BY Salary),
    rn = ROW_NUMBER() OVER (ORDER BY Salary)
  FROM @salary
)
SELECT EmpID, Salary, r, dr, rn FROM x;
Run Code Online (Sandbox Code Playgroud)

结果:

EmpID  Salary   r   dr  rn
-----  ------   --  --  --
5      12000    1   1   1
4      37000    2   2   2
7      50000    3   3   3
8      54000    4   4   4
3      54000    4   4   5
6      69000    6   5   6
2      80000    7   6   7
1      90000    8   7   8
Run Code Online (Sandbox Code Playgroud)

我不认为你想用RANK()这个特定的问题,因为它的工作方式没有第 5 位,例如。所以现在归结为是否要在平局的情况下包含多行,如果不是,是否需要基于某些条件的任意行或特定行。所以稍微调整一下语句:

-- if you want ties:
;WITH x AS
(
  SELECT EmpID, Salary, 
    dr = DENSE_RANK() OVER (ORDER BY Salary)
  FROM @salary
)
SELECT EmpID, Salary FROM x WHERE dr = 4;

-- results:
-- 3   54000
-- 8   54000

-- to take the *lowest* EmpID:
;WITH x AS
(
  SELECT EmpID, Salary, 
    rn = ROW_NUMBER() OVER (ORDER BY Salary, EmpID)
  FROM @salary
)
SELECT EmpID, Salary FROM x WHERE rn = 4;

-- results:
-- 3   54000

-- to take the *highest* EmpID:
;WITH x AS
(
  SELECT EmpID, Salary, 
    rn = ROW_NUMBER() OVER (ORDER BY Salary, EmpID DESC)
  FROM @salary
)
SELECT EmpID, Salary FROM x WHERE rn = 4;

-- results:
-- 8   54000
Run Code Online (Sandbox Code Playgroud)


ype*_*eᵀᴹ 6

编写此查询的另一种方法是使用 2012+OFFSET / FETCH语法来查找第 N 个薪水:

; WITH Nth AS                    -- To find the Nth highest salary,
( 
  SELECT DISTINCT Salary         -- get all the distinct salary values
  FROM Employee
  ORDER BY Salary DESC           -- order them from high to low
  OFFSET 3 ROWS                  -- skip (N-1) values
  FETCH NEXT 1 ROWS ONLY         -- and keep the next one (Nth).
)
SELECT EmpID, Salary                       -- Then show 
FROM Employee                              -- all employees that have
WHERE Salary = (SELECT Salary FROM Nth) ;  -- have a salary equal to that.
Run Code Online (Sandbox Code Playgroud)

或者对于 2012 之前的版本,分 2 个步骤。首先按 排序DESC,然后按ASC

; WITH TopN AS                     -- Find the top N salaries,
(
  SELECT DISTINCT TOP (4) Salary
  FROM Employee
  ORDER BY Salary DESC
),
  Nth AS                           -- then keep only the Nth one,
( 
  SELECT TOP (1) Salary
  FROM TopN
  ORDER BY Salary
)
SELECT EmpID, Salary                       -- and show 
FROM Employee                              -- all employees that have
WHERE Salary = (SELECT Salary FROM Nth) ;  -- have a salary equal to that.
Run Code Online (Sandbox Code Playgroud)

SQLfiddle 中测试


Jeh*_*aki 4

如果N=4,则返回有4-1=3个较高薪水的薪水,换句话说,返回第4高的薪水。

例子:

Salaries (500, 400, 400, 300, 250, 200). 
Run Code Online (Sandbox Code Playgroud)

期望的结果是 (250)(第四个,因为我们只计算“400”一次DISTINCT)。N-1=3表示有3个不同的工资大于250,分别是(500,400,300)。

在你的例子中,没有重复的工资,期望的结果是(5400),这是第四高的。因此,查询返回工资,其中较高工资的计数为 4-1。