2017-10-24 6 views
1

Ich versuche, das zweithöchste Gehalt in jeder Abteilung zu finden.Zweithöchstes Gehalt in jeder Abteilung

Schema:

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

Beispielsätze:

/*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); 

Meine Frage:

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) 

Der Ausgang ich bekommen habe ist, wie unten;

departmentid NAME salary 

1    Joe  70000 

1    Randy 70000 

2    SAM  60000 

3    Janet 69000 

Meine erwartete Ausgabe

departmentid NAME salary 

1    Joe  70000 

1    Randy 70000 

2    SAM  60000 

3    NULL  NULL 

ist Da es nur einen Datensatz für DepartmentID ist = 3, sollte es null zurück.

Was ist falsch an dieser Abfrage? Gibt es andere Möglichkeiten, dieses Ergebnis zu erzielen?

Ich habe auch eine SQL fiddle enthalten.

+1

Bitte lesen Sie [Warum sollte ich einen MCVE für das, was mir scheint eine sehr einfache SQL-Abfrage zu sein?] (Https://meta.stackoverflow.com/questions/ 333952/why-soll-ich-biete-eine-mcve-für-was-scheint-zu-mir-sein-eine-sehr-einfache-sql-Abfrage). Ihre Frage sollte * Ihre Frage enthalten *, kein Link zu einem anderen Ort, an dem Ihre eigentliche Frage zu finden ist. – AakashM

Antwort

1

Ich habe zwei CTEs verwendet.

Die erste gibt eine Liste aller Abteilungen zurück. Sie werden dies benötigen, um sicherzustellen, dass Abteilungen mit weniger als 2 Gehältern im Endergebnis enthalten sind.

Der zweite Rang zählt jeden Mitarbeiter in seiner Abteilung.

Schließlich habe ich eine left outer join verwendet, um die vollständige Liste der Abteilungen zu pflegen.

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 
; 

Returns

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

zurückgibt Es funktioniert .. Danke :) –

3

ROW_NUMBER() und wählen = 2

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

eine Sub-Abfrage verwenden, wie ich hier schrieb:

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

Edit: 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

Es gibt auch eine einfache Möglichkeit, : Dies gibt nur die zweithöchste Gesamtsumme zurück

+0

Wenn ich diese Abfrage ausführen, gibt es Henry, der ist der Top-Verdiener in der Abteilung 2. –

+0

Mein Fehler, der die insgesamt zweithöchsten – Coffeegrinder

0

Wenn das Departmentid nur eine Zeile hat, und wenn Sie das auch berücksichtigen. Dann

Abfrage

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