每个部门的第二高工资

时间:2017-10-24 08:16:54

标签: sql-server

我想找到每个部门的第二高薪。

架构:

CREATE TABLE employees
( 
    ID int NOT NULL,
    NAME char(50) NOT NULL,
    departmentid int,
    salary int 
);

样本记录:

/*departmentid =1 */
INSERT INTO employees VALUES (1, 'Max', 1, 90000);
INSERT INTO employees VALUES (2, 'Joe', 1, 70000);
INSERT INTO employees VALUES (3, 'Randy', 1, 70000);

/*departmentid =2 */
INSERT INTO employees VALUES (4, 'Henry', 2, 80000);
INSERT INTO employees VALUES (5, 'SAM', 2, 60000);

/*departmentid =3 */
INSERT INTO employees VALUES (6, 'Janet', 3, 69000);

我的查询:

SELECT departmentid, 
    NAME, 
    salary 
FROM   
    (
        SELECT 
            departmentid, 
            NAME, 
            salary, 
            Dense_rank()OVER (partition BY departmentid 
                          ORDER BY salary DESC) AS Rank, 
             Count(1)OVER(partition BY departmentid) AS cnt 
        FROM   
            employees
    )t 
WHERE  
    t.rank = 2 
    OR ( t.rank = 1 
         AND cnt = 1 ) 

我得到的输出如下;

departmentid   NAME    salary

1              Joe      70000

1              Randy    70000

2              SAM      60000

3              Janet    69000

我的预期输出

departmentid   NAME    salary

1              Joe      70000

1              Randy    70000

2              SAM      60000

3              NULL     NULL

由于departmentid = 3只有一条记录,它应该返回null。

此查询有什么问题?有没有其他方法可以达到这个结果?

我还添加了SQL fiddle

6 个答案:

答案 0 :(得分:3)

ROW_NUMBER()并选择= 2

   ;WITH salary AS
    (
     [RN] = SELECT ROW_NUMBER() OVER (PARTITION BY departmentid ORDER BY salary),*
    FROM <table>
    )
    SELECT 
    *
    FROM salary
    WHERE [RN] = 2 

答案 1 :(得分:1)

我使用了两个CTEs

第一个返回每个部门的列表。您需要这样才能确保最终结果中包含少于2个工资的部门。

第二个对每个部门的员工进行排名。

最后,我使用了left outer join来维护完整的部门列表。

WITH Department AS
(
  -- Returns a list of the departments.
  SELECT 
    departmentid
  FROM
    employees
  GROUP BY
    departmentid
),
EmployeeRanked AS
(
  SELECT
    DENSE_RANK() OVER (PARTITION BY departmentid ORDER BY salary DESC) AS [Rank],
    departmentid,
    NAME,
    salary
  FROM
    employees
)
SELECT 
  er.Rank,
  d.departmentid,
  er.NAME,
  er.salary
FROM 
  Department AS d
    LEFT OUTER JOIN EmployeeRanked AS er    ON er.departmentid = d.departmentid
                                            AND er.[Rank] = 2
;

返回

Rank    departmentid    NAME    salary
2       1               Joe     70000
2       1               Randy   70000
2       2               SAM     60000
(null)  3               (null)  (null)

答案 2 :(得分:0)

使用我在此处写的子查询:http://sqlfiddle.com/#!6/bb5e1/26

 with ranks as(
 SELECT departmentid, 
       salary,
       row_number() over (partition by (departmentid) order by salary desc) as rank
FROM   employees
   )
   Select * 
   from ranks
Where ranks.rank = 2

答案 3 :(得分:0)

还有一种简单的方法:

SELECT TOP 1 * FROM (Select top 2 * FROM employees order by salary desc ) e Order by salary asc

编辑:这只返回第二高的整体

答案 4 :(得分:0)

如果离开只有一行,如果你也考虑到了。然后

<强>查询

;with cte as(
  select [rank] = dense_rank() over(
    partition by departmentid
    order by departmentid, salary desc
  ), *
  from employees
)
select ID, NAME, departmentid, salary from cte
where [rank] = 2
union all
select max(ID), max(NAME), departmentid, max(salary)
from cte
group by departmentid
having count([rank]) = 1;

答案 5 :(得分:0)

我认为您只需从代码中删除以下代码即可得到正确答案

OR ( t.rank = 1 
         AND cnt = 1 ) 

该结果的主表也应保持连接状态,以在其余列中获取空值