2017-09-22 64 views
5

Potrzebuję znaleźć 3rd maximum salary dla pracownika dla każdego działu w table. jeśli nie istnieje 3rd maximum salary, to wyświetl numer 2nd maximum salary. jeśli nie istnieje 2nd maximum salary, znajdź highest salary. Jak osiągnąć ten wynik w sql-server?Znajdź 3 najwyższe wynagrodzenie dla każdego działu na podstawie danych tabeli

Struktura table podano poniżej

create table employee1(empid int, empname varchar(10), deptid int, salary money) 

insert into employee1 
select 1,'a',1, 1000 
union 
select 1,'b',1, 1200 
union 
select 1,'c',1, 1500 
union 
select 1,'c',1, 15700 
union 
select 1,'d',2, 1000 
union 
select 1,'e',2, 1200 
union 
select 1,'g',3, 1500 

Próbowałem wspólny sposób na uzyskanie maksymalnego wynagrodzenia dla poszczególnych kategorii przy użyciu row_number funkcję.

;with cte 
as 
( 
select ROW_NUMBER() over(partition by deptid order by salary) as id, * from employee1 
) 
select * from cte 
+2

Co jeśli istnieją więzi? Czy chcesz obie rekordy wiążące? A w takim razie, co jeśli 1 osoba ma najwyższą pensję, a 2 osoby są związane na sekundę, czy chcesz 3. najwyższą pensję (4 osoba) lub jedną z drugich? – Matt

+0

yeah..i zmieniłaby wartość row_number na dense_rank, aby adresować krawaty. – bmsqldev

+1

Uaktualniłem odpowiedź za pomocą więzów, których potrzebujesz po prostu zastąpić number_wiersza() dense_rank() – Matt

Odpowiedz

3
Select EmpID,empname,deptid,salary 
From (
Select * 
     ,RN = Row_Number() over (Partition By deptid Order By Salary) 
     ,Cnt = sum(1) over (Partition By deptid) 
From employee1 
    ) A 
Where RN = case when Cnt<3 then Cnt else 3 end 

Returns

enter image description here

+0

, podobnie jak hrabia, nie pomyślał o tym. ale nie działa, jeśli istnieją powiązania i używa DENSE_RANK(), aby uzyskać je zamiast ROW_NUBMER(). Ale na pewno będę chciał dodać to do mojego arsenału :) – Matt

+1

@Matt Prawidłowo, ku mojemu wstydowi, nawet nie brałem pod uwagę więzi. : - \ –

3

Odpowiedź będzie zależała, jeśli chcesz powiązania i jak sobie z nimi radzić. Jeśli nie chcesz mieć żadnych więzi, a nawet jeśli jeden z nich ma do czynienia z inną, staje się kolejną najwyższą pensją, to wystarczy użyć numeru row_number, takiego jak ten, który wyświetlasz tylko przy malejącej pensji, a następnie użyć innego row_number, aby go odwrócić. Jeśli nie chcesz korzystać row_number po raz drugi można zrobić z kilkoma innymi technikami jak dobrze, ale krok 1 jest znaleźć najwyższy etap 2 jest odwrócenie tej kolejności

; WITH cteRankSalariesByDepartment AS (
    SELECT 
     * 
     ,RowNum = DENSE_RANK() OVER (PARTITION BY deptid ORDER BY salary DESC) 
    FROM 
     employee1 
) 

, cteReverseRankHighestSalaries AS (
    SELECT 
     * 
     ,RowNum2 = DENSE_RANK() OVER (PARTITION BY deptid ORDER BY RowNum DESC) 
    FROM 
     cteRankSalariesByDepartment 
    WHERE 
     RowNum <= 3 
) 

SELECT * 
FROM 
    cteReverseRankHighestSalaries 
WHERE 
    RowNum2 = 1 

Per komentarz zaktualizowanego do DENSE_RANK() mogłeś po prostu użyj go zamiast row_number(), a dostaniesz swoje krawaty.

+0

Zwraca on całkowicie błędne wyniki w niektórych przypadkach: http://rextester.com/OTTA88582 –

+0

@ RadimBača Nie jestem pewien czy skomentowałeś na złą odpowiedź, ale twoje oświadczenie i przykład nie mają związku z tą odpowiedzią. W twoim przykładzie masz poprawne zamówienie i używasz row_number zamiast gęstej rangi dla krawatów. Najpierw musisz złożyć zlecenie poprzez obniżenie wynagrodzenia, które postawi najwyższą pensję jako rząd 1, a następnie posortujesz pensję ascend, która stawia najniższy z nich jako rząd 1, ponieważ rownum można rozsądnie użyć jako surogatu, o ile go używasz zejście, które działa też – Matt

+1

przepraszam Popełniłem błąd, twoja odpowiedź jest w porządku. –

1

można spróbować kwerendy jak poniżej:

select * from 
(
select 
empid, 
empname , 
deptid , 
salary , 
ROW_NUMBER() over(partition by deptid order by id desc) as rev_id 
from 
( 
select 
ROW_NUMBER() over(partition by deptid order by salary) as id, 
empid, 
empname , 
deptid , 
salary 
from employee1 
) 
t where id<=3 
)t where rev_id=1 

working demo

1

Można użyć UNION

;with cte 
as 
( 
select ROW_NUMBER() over(partition by deptid order by salary) as id, * from employee1 
) 

--get the 3rd highest 
select 
    * 
from cte 
where id = 3 

union 

--get the highest/max 
select 
    c.* 
from cte c 
--this determines the highest which salary for each dept 
inner join 
    (select deptid, max(id) id 
    from cte 
    group by deptid) x on x.deptid = c.deptid and x.id = c.id 
--this limits it on depts that aren't in the list in the first part of the query 
where 
    c.deptid not in (select deptid from cte where id = 3) 
2

Wystarczy kwerendy liczyć potrzeby i ROW_NUMBER z warunku jak poniżej:

;with cte 
as 
( 
select ROW_NUMBER() over(partition by deptid order by salary desc) as id, 
    Cnt = count(*) over(partition by deptid), * from employee1 
) 
select * from cte where (cnt >= 3 and id = 3) 
or (cnt < 3 and id = 1) 
-1

Aby zwiększyć swoje pytanie Dodałem dwóch pracowników z tego samego wynagrodzenia w trzecim położeniu.

Aby to uzyskać, musisz otrzymać pierwszą sumę wg pensów według działu. Po trzeba odwrócić l rangę wynagrodzenia i uzyskać pozycję 1

spróbować

DECLARE @employee1 TABLE 
     ( 
     empid INT, 
     empname VARCHAR(10), 
     deptid INT, 
     salary MONEY 
    ) 

    INSERT @employee1 Values 
    (1,'a',1, 1000 ) 
,(1,'b',1, 1200) 
,(2,'bb',1, 1200) 
,(1,'c',1, 1500) 
,(3,'ccc',1, 1500) 
,(1,'c',1, 15700) 
,(1,'d',2, 1000) 
,(1,'e',2, 1200) 
,(1,'g',3, 1500) 

    WITH cte_rank 
     AS (SELECT Dense_rank() 
         OVER ( 
         partition BY deptid 
         ORDER BY salary) SalaryRank, 
        * 
      FROM @employee1), 
     cte_final 
     AS (SELECT Dense_rank() 
         OVER ( 
         partition BY deptid 
         ORDER BY salaryrank DESC) SalaryRankReverse, 
        * 
      FROM cte_rank 
      WHERE salaryrank <= 3) 
    SELECT * 
    FROM cte_final 
    WHERE salaryrankreverse = 1 

Wynik

SalaryRankReverse SalaryRank   empid  empname deptid  salary 
-------------------- -------------------- ----------- ---------- ----------- --------------------- 
1     3     1   c   1   1500.00 
1     3     3   ccc  1   1500.00 
1     2     1   e   2   1200.00 
1     1     1   g   3   1500.00 
+1

Odpowiedź na zajęcie 1 za trzecią najwyższą pensję to empid 1 i 2 na 1200,00. masz ORDER BY odwrócone na swoje ctes, ale kiedy to naprawisz, przedstawisz odpowiedź, którą już napisałem – Matt