2017-01-09 23 views
19

Mam uruchomione poniżej zapytanie, aby uzyskać 3. najwyższe wynagrodzenie z tabeli pracowników i działało poprawnie, ale nie mogę zrozumieć jego logiki. W jaki sposób wartości podokresów pasują do zapytania głównego (lewa część). Czy ktoś może wyjaśnić, jaka jest logika działania tego zapytania?Co to jest logika działająca za tym zapytaniem?

select e1.salary 
from employee as e1 
where 3 = (select count(salary) 
      from employee as e2 
      where e1.salary<=e2.salary) 

PS: Mogę zrozumieć numer count() powraca wierszy (gdzie wszystkie rekordy są unikalne).

+6

Dla kogoś na bardzo podstawowym poziomie zrozumienia; dlaczego to tak skomplikowane? Nie możesz tego zrobić za pomocą RANK lub ROW_NUMBER w połączeniu z ORDER BY? Czy jest jakaś dziedziczona wartość, robiąc to jak przykład OP? –

+2

@StianYttervik Zgaduję, że ktokolwiek to napisał, nie wie, że RANK lub ROW_NUMBER istnieją. – Caleth

+2

OK, bliscy wyborcy. Do diabła z tobą wszystko jest nie tak? To jest * nigdzie blisko * pytania rekomendacyjnego. (Poważnie, skąd go wziąłeś?) Pytanie jest wystarczająco jasne, o czym świadczy kilka fajnych odpowiedzi wyjaśniających, co robi zapytanie. Powiedziałbym nawet, że to pytanie nie jest "podstawowe"; nie jest nierozsądne, że jest ono mylone z tym zapytaniem, gdy wciąż chwyta się podstaw SQL. (Heck, nawet jeśli znasz sposób, w jaki działa SQL, może to chwilę potrwać, zanim się zorientujesz.) Jeśli chcesz zagłosować, aby zamknąć, * najpierw wymyśl dobry powód *. – jpmc26

Odpowiedz

5

Każda pensja w tabeli employee zostanie przekazana do sub-query. Sub-query znajdzie wszystkie salaries te są mniej niż przekazane salary i policz.

Dla przekazywane wynagrodzenia, jeżeli powróci sub-query liczyć jako 3 wtedy wola wynagrodzenie spowodowało

rozważyć istnieje 5 rekordy w tabeli employee

1 
2 
3 
4 
5 
6 
7 
8 

gdy 1 jest przekazywana z e1 Zapytanie podrzędne będzie podobne do

teraz licznik wewnątrz sub-zapytania będzie 8, ponieważ wszystkie rekordy są większe lub równe 1. hrabiego nie jest równe 3 tak salary 1 nie będą zwracane


gdy 2 jest przekazywana z e1, sub-query będzie jak

select e1.salary 
from employee as e1 
where 3 = (select count(salary) 
      from employee as e2 
      where 2<=e2.salary) 

teraz licznik wewnątrz sub-zapytania będzie 7 bo z wyjątkiem 1 Wszystkie zapisy są większe lub równe 2. hrabiego nie jest równa 3 tak Salary 2 nie będzie zwrócono


gdy 6 jest przekazywana z e1, sub-query będzie jak

select e1.salary 
from employee as e1 
where 3 = (select count(salary) 
      from employee as e2 
      where 6<=e2.salary) 

Obecnie istnieją trzy rekordy większa niż lub równa 6 (IE) 6,7,8 więc liczyć będzie 3 a warunek jest spełniony. Tak więc salary 6 zostanie zwrócony

+0

lub masz na myśli 6 <= 6 –

+0

@JasonClark - Przepraszamy Nie dostałem tego .. –

+0

Chcę wyczyścić proces podkwerendy po klauzuli Where, przypuśćmy, jeśli mam 4 rekordy, takie jak 25000, 15000, 10000, 17000. to w jaki sposób podzapytanie będzie wykonać na tych wartościach, jeśli chcę uzyskać 3. najwyższą pensję? –

1

W rzeczywistości jest to dość proste. Drugie zapytanie wybiera wszystkich pracowników, dla których aktualny (wybrany) pracownik (e1) ma niższe wynagrodzenie. Następnie mówimy, że liczba pracowników o niższym lub równym wynagrodzeniu musi wynosić 3, co skutkuje uzyskaniem 3. najwyższej pensji.

21

To zapytanie jest w zasadzie mówiąc:

for each row in employee assign to e1 
    count = 0 
    for each row in employee assign to e2 
     if e1.salary <= e2.salary 
      count = count + 1 
     end if 
    end for 
    if count = 3 
     add e1 to result set 
    end if 
end for 
return result set 

Podsumowując dla każdego wiersza w tabeli employee, do którego przybywa stole po raz drugi i liczenia liczby wierszy z niższej lub równej pensji. Jeśli są dokładnie 3, doda wiersz do wyniku.

Warto zauważyć, że może się to nie udać, jeśli jest więcej niż jeden pracownik o tym samym wynagrodzeniu. Prawdopodobnie potrzebujesz zapytania z funkcją rankingu. Coś takiego:

SELECT salary 
FROM 
    (SELECT 
     salary 
     ,DENSE_RANK() OVER (ORDER BY salary DESC) [rank] 
    FROM employee) t 
WHERE 
    [rank] = 3 

To, co dokładnie oznacza "3. najwyższy", jest być może trochę niejednoznaczne. Jeśli mamy pensje 8, 8, 6, 5 powyżej powróci 5. Jeśli chcieliśmy 6 trzeba byłoby zmienić DENSE_RANK do row_number tak:

SELECT salary 
FROM 
    (SELECT 
     salary 
     ,ROW_NUMBER() OVER (ORDER BY salary DESC) [rank] 
    FROM employee) t 
WHERE 
    [rank] = 3 

Wersja DENSE_RANK powyżej cierpi również z powrotem wiele wierszy jeśli jest remis na trzecie miejsce. To, czy jest to pożądane, czy też nie, zależy dokładnie od tego, co jest wymagane, ale można je obniżyć, używając funkcji agregującej na wynagrodzeniu.

SELECT MAX(salary) 
FROM 
    (SELECT 
     salary 
     ,DENSE_RANK() OVER (ORDER BY salary desc) [rank] 
    FROM employee) t 
WHERE 
    [rank] = 3 
6

Rozważmy następujące wartości:

Salary: 
1 
2 
3 
4 
5 
6 
7 
8 

e1 e2 
1 1 
2 2 
3 3 
4 4 
5 5 
6 6 
7 7 
8 8 

Na e1.1 znajduje się 8 wierszy e2, które są większe lub równe e1.1.

Dla e1.2 jest 7 wierszy w e2, które są większe lub równe e1.2.

...

Dla e1.6 są 3 wiersze e2 które są większe lub równe e1.6.

To dość dziwne i mylące stwierdzenie. Chciałbym po prostu przepisać go za pomocą DENSE_RANK funkcję okna, bo jeśli masz kilka wierszy z tego samego wynagrodzenia, nie będzie uzyskać poprawne wyniki:

DECLARE @t TABLE (i INT) 
INSERT INTO @t 
VALUES (1), 
     (2), 
     (3), 
     (4), 
     (5), 
     (6), 
     (8), 
     (8); 


WITH cte 
      AS (SELECT * , 
         DENSE_RANK() OVER (ORDER BY i DESC) AS rn 
       FROM  @t 
      ) 
    SELECT * 
    FROM cte 
    WHERE rn = 3 

wyniki w 5 podczas początkowej SELECT spowoduje 6 że wierzę nie jest wcale trzecią najwyższą pensją.

+2

Dla większości osób "Trzecia najwyższa pensja" oznacza pensję trzeciej osoby o najwyższej pensji, więc oczekiwany wynik 5, 6, 8, 8 wynosiłby 6. –