Что такое логика, работающая над этим запросом?
Я выполняю нижеприведенный запрос, чтобы получить 3-е высшее зарплату из таблицы сотрудников, и он работал правильно, но я не могу понять его логику. Как значения подзапроса совпадают с основным запросом (левая часть). Может кто-нибудь объяснить, что логика работает за этим запросом?
select e1.salary
from employee as e1
where 3 = (select count(salary)
from employee as e2
where e1.salary<=e2.salary)
PS: Я понимаю, что count()
возвращает количество строк (где все записи уникальны).
Ответы
Ответ 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-ей самой высокой зарплаты.