2017-10-24 5 views
1

私は各部門で2番目に高い給料を探しています。各部門で2番目に高い給与

スキーマ:

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 = 3のためのレコードは1つだけであり、それはnullを返す必要があります

departmentid NAME salary 

1    Joe  70000 

1    Randy 70000 

2    SAM  60000 

3    NULL  NULL 

です。

このクエリで何が問題になっていますか?この結果を達成するための他の方法はありますか?

また、SQL fiddleも含まれています。

+1

[なぜ私は非常に単純なSQLクエリであることを私には思える何のためにMCVEを提供する必要があります?]読みください(https://meta.stackoverflow.com/questions/ 333952/what-should-i-provide-an-mcve-for-what-like-to-a-very-simple-sql-query)を使用すると、あなたの質問にはあなたの質問*が含まれていて、あなたの実際の質問が見つかるはずの他の場所へのリンクではありません。 – AakashM

答えて

1

私は2つのCTEsを使用しました。

最初はすべての部門のリストを返します。最終的な結果に給与が2未満の部署が含まれるようにするには、これが必要です。

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) 
+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 
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 
0

を簡単な方法もあります:

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

編集:全体で2番目に高い値を返します

+0

このクエリを実行すると、部門2の上位入賞者であるHenryが返されます。 –

+0

私の間違いは全体的に2番目に高い値を返します – Coffeegrinder

0

行が1つしかない場合は、それも考慮する場合。その後

クエリ

;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;