Ссылка на родительский запрос внутри дочернего запроса - PullRequest
0 голосов
/ 22 января 2020

Может кто-нибудь объяснить этот запрос, когда подзапрос ссылается на родителя. Как SQL думает об этом

Второй по величине оклад сотрудника:

select max(e1.sal),e1.deptno 
from s_emp e1 
where sal < (select max(sal) from s_emp e2 where e2.deptno = e1.deptno) 
group by e1.deptno;

Я проверил это, и оно работает.

Ответы [ 2 ]

0 голосов
/ 22 января 2020

Это называется коррелированным подзапросом , поскольку результат подзапроса потенциально различен для каждой строки внешнего запроса.

Когда MySQL выполняет запрос, вы можете подумать это как foreach l oop над коллекцией. Например, в синтаксисе PHP:

foreach (s_emp as e1) {
  ...
}

Он должен запустить подзапрос для каждой строки внешнего запроса, прежде чем он сможет оценить сравнение <. Это станет довольно дорогим, поскольку количество рядов увеличивается. Если таблица имеет N строк, она будет выполнять подзапрос N раз, даже если для deptno есть только несколько отдельных значений! MySQL не достаточно умен, чтобы запомнить результат после выполнения подзапроса для того же значения deptno.

Вместо этого вы можете получить результат таким способом, который вычислит max (sal) для всех deptnos, и сохраните эти результаты во временной таблице.

select max(e1.sal), e1.deptno
from s_emp e1
join (select deptno, max(sal) as max_sal from s_emp group by deptno) as e2
  on e1.deptno = e2.deptno
where e1.sal < e2.max_sal
group by e1.deptno

Цель этого запроса, по-видимому, состоит в том, чтобы вернуть вторую наивысшую зарплату на отдел, верно?

Вот еще одно решение с использованием оконных функций в MySQL 8.0:

select deptno, sal
from (
  select deptno, sal, dense_rank() over (partition by deptno order by sal desc) as dr
  from s_emp
) as e1
where dr = 2
0 голосов
/ 22 января 2020

Сначала удалите group by и aggegation и рассмотрите этот запрос:

select e1.sal, e1.deptno 
from s_emp e1 
where e1.sal < (select max(sal) from s_emp e2 where e2.deptno = e1.deptno)

Возвращает все строки таблицы, за исключением строк с максимальным значением sal в их deptno. Почему? Потому что sal в каждой строке сравнивается с максимальной зарплатой deptno и должно быть меньше. Подзапрос в предложении WHERE выполняется один раз для каждой строки таблицы:

select max(e2.sal) from s_emp e2 where e2.deptno = e1.deptno

, и для каждой строки он возвращает максимум sal для текущей строки deptno. Таким образом, результатом являются все sal с, которые меньше, чем этот максимальный sal из текущей строки deptno. Теперь, если вы добавите group by deptno и агрегацию, вы получите для каждого deptno максимальный sal возвращаемых строк, который является 2nd наивысшим sal для каждого deptno, так как все верхние уже исключено.

...