Подтвердить что ты не робот

Что такое логика, работающая над этим запросом?

Я выполняю нижеприведенный запрос, чтобы получить 3-е высшее зарплату из таблицы сотрудников, и он работал правильно, но я не могу понять его логику. Как значения подзапроса совпадают с основным запросом (левая часть). Может кто-нибудь объяснить, что логика работает за этим запросом?

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

PS: Я понимаю, что count() возвращает количество строк (где все записи уникальны).

4b9b3361

Ответ 1

Каждая зарплата в таблице employee e1 будет передана sub-query. sub-query найдет все salaries, которые меньше пройденного salary и посчитают его.

За полученную зарплату, если подзапрос возвращает счет как 3, тогда эта зарплата будет

считают, что в таблице employee есть 5 записей

1
2
3
4
5
6
7
8

когда 1 передается из e1, подзапрос будет выглядеть как

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

теперь подсчет внутри суб-запроса будет равен 8, потому что все записи больше или равны 1. Count не равно 3, поэтому salary 1 не будет возвращен


когда 2 передается из e1, подзапрос будет выглядеть как

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

теперь подсчет внутри суб-запроса будет равен 7, поскольку кроме 1 все записи больше или равны 2. Count не равно 3, поэтому Salary 2 он не будет возвращен


когда 6 передается из e1, подзапрос будет выглядеть как

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

Теперь есть три записи, большие или равные 6 (т.е.) 6,7,8, поэтому счет будет равен 3, и условие выполнено. Таким образом, salary 6 будет возвращен

Ответ 2

Этот запрос в основном говорит:

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

В сводке для каждой строки в таблице сотрудников она посещает таблицу второй раз и подсчитывает количество строк с более низкой или равной зарплатой. Если есть ровно 3, он добавит строку к результату.

Стоит отметить, что это может пойти не так, если есть более одного сотрудника с одинаковой зарплатой. Вероятно, вам нужен запрос с функцией ранжирования. Что-то вроде этого:

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

То, что именно подразумевается под "3-м наивысшим", возможно, несколько неоднозначно. Если у нас есть зарплаты 8, 8, 6, 5, то это вернет 5. Если нам нужно 6, вам нужно будет изменить DENSE_RANK на ROW_NUMBER следующим образом:

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

Версия DENSE_RANK выше также страдает возвратом нескольких строк, если есть связь за третье место. Является ли это желательным или нет, зависит от того, что требуется, но это можно сократить, используя совокупную функцию по зарплате.

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

Ответ 3

Рассмотрим следующие значения:

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

В e1.1 есть 8 строк в e2, которые больше или равны e1.1.

В e1.2 есть 7 строк в e2, которые больше или равно e1.2.

...

Для e1.6 есть 3 строки в e2, которые больше или равны e1.6.

Это довольно странный и запутанный оператор select. Я бы просто переписал его с помощью функции окна DENSE_RANK, потому что если у вас несколько строк с одинаковой зарплатой, вы не получите правильных результатов:

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

Результаты в 5, в то время как ваш исходный оператор select приведет к 6, который, по моему мнению, не является третьим по величине зарплатой.

Ответ 4

На самом деле это довольно просто. Второй запрос выбирает всех сотрудников, для которых текущий (выбранный) сотрудник (e1) имеет более низкую зарплату. Затем мы говорим, что число сотрудников с более низкой или равной зарплатой должно быть 3. Каковы результаты получения 3-ей самой высокой зарплаты.