Понимание запроса - Select 1 from
Задача:
Найти сотрудника с самой высокой зарплатой среди каждого отдела
Данные:
CREATE SEQUENCE employee_id_seq;
create table Employee
(
id_emp int DEFAULT nextval('employee_id_seq')
NOT NULL PRIMARY KEY UNIQUE,
name_emp varchar(255) NOT NULL,
mgr_id_fk int not null,
job_emp text NOT NULL,
salary int NOT NULL,
date_emp date NOT NULL,
dep_ID_fk int NOT NULL
);
ALTER SEQUENCE employee_id_seq
OWNED BY employee.id_emp;
create table Manager
(
id_mgr int not null primary key unique,
type_mgr varchar(255)
);
ALTER table Employee
add FOREIGN KEY (mgr_id_fk) REFERENCES Manager (id_mgr)
on update cascade
on delete set null;
create table Department
(
id_depart int NOT NULL PRIMARY KEY unique,
name_depart varchar(255) not null,
address text,
phone text
);
insert into Manager (id_mgr, type_mgr)
VALUES
(1006, 'juniormgr'),
(1004, 'middlemgr'),
(1005, 'seniormgr');
insert into Department (id_depart, name_depart, address, phone)
values (1, 'Sales', 'Sydney', '0425 198 053'),
(2, 'Accounts', 'Melbourne', '0429 198 955'),
(3, 'Admin', 'Melbourne', '0428 198 758'),
(4, 'Marketing', 'Sydney', '0427 198 757');
insert into Employee(id_emp, name_emp, mgr_id_fk, job_emp, salary, date_emp, dep_ID_fk)
values (nextval('employee_id_seq'), 'ken Adams', 1006, 'Salesman', 70000, '2008-04-12', 1),
(nextval('employee_id_seq'), 'Ru Jones', 1004, 'Salesman', 65000, '2010-01-18', 1),
(nextval('employee_id_seq'), 'Dhal Sim', 1006, 'Accountant', 88000, '2001-03-07', 2),
(nextval('employee_id_seq'), 'Ellen Honda', 1006, 'Manager', 118000, '2001-03-17', 1),
(nextval('employee_id_seq'), 'Mike Bal', 1005, 'Receptionist', 68000, '2006-06-21', 3),
(nextval('employee_id_seq'), 'Martin Bison', 1005, 'CEO', 210000, '2010-07-12', 3),
(nextval('employee_id_seq'), 'Shen Li', 1004, 'Salesman', 86000, '2014-09-18', 1),
(nextval('employee_id_seq'), 'Zang Ross', 1004, 'Salesman', 65000, '2017-02-02', 1),
(nextval('employee_id_seq'), 'Sagar Kahn', 1005, 'Salesman', 70000, '2016-03-01', 1);
Вот такой запрос выдаст нужную информацию :
select * from employee e
where not exists (select 1 from employee e2
where e2.dep_id_fk = e.dep_id_fk
and e2.salary > e.salary);
Мои рассуждения:
- Сначала выполнится подзапрос и Postgres сохранит этот временный результат
- затем будет выполнится остальная часть запроса
select * from employee e
where not exists ...
где not exists исключит все совпадения найденные в подзапросе
Вопрос :
Данный код вызывает непонимание, как же все таки это работает, потому что здесь все не логично на мой взгляд.
Например, как работает вот это
select 1 from employee e2
where e2.dep_id_fk = e.dep_id_fk
and e2.salary > e.salary
select 1 from - что он вообще делает ?
e2.dep_id_fk = e.dep_id_fk - это проверка одной и той же таблицы ( в подзапросе и в основном запросе), но зачем ?
e2.salary > e.salary - а это вот зачем ?
Кто-нибудь может подробно пояснить эти моменты, особенно применение select 1 from
Обновление (на основе комментариев):
снова мои рассуждения:
select 1 from employee e2 - сама по себе, это строка будет возвращать по одной записи и сравнивать их с записями каждой строки из внешнего запроса (выражение-пустышка, только чтобы взять для перебора строку)
e2.salary > e.salary - например, найдены записи с одинаковым департаментом и несколькими разными зарплатами в конкретном департаменте. Из под-запроса выбирается некий департамент и сравнивается с департаментом из внешнего запроса и когда найдется соответствие, тогда происходит сравнение зарплат между сотрудниками данного департамента :
where 3(подзапрос) = 3 (внешний запрос)
and 210 000 (подзапрос) > 68 000 (внешний запрос)
результат будет true, но not exists, инвертирует его в false, поэтому такая запись не попадет в результирующий (внешний) запрос;
where 3(подзапрос) = 3 (внешний запрос)
and 210 000 (подзапрос) > 210 000 (внешний запрос)
результат будет false, но not exists, инвертирует его в true, поэтому такая запись попадет в результирующий (внешний) запрос и это будет запись о сотруднике с максимальной зп для текущего департамента;
Ответы (1 шт):
Мои рассуждения:
Сначала выполнится подзапрос и Postgres сохранит этот временный результат
Неверно. Подзапрос будет выполняться для каждой отдельной записи первой копии таблицы. Конечно, реально запрос может быть выполнен иначе, но логика SQL-текста именно такая.
select 1 from - что он вообще делает ?
WHERE EXISTS просто проверяет, что запись существует. WHERE NOT EXISTS просто проверяет, что записи не существует.
При это абсолютно всё равно, что в той записи - важен сам факт её существования. Можно в SELECT писать что угодно - единицу, ноль, строку, дату, NULL... значение всё равно будет проигнорировано. Будет зарегистрирован только факт, что запись нашлась или не нашлась.
e2.dep_id_fk = e.dep_id_fk - это проверка одной и той же таблицы ( в подзапросе и в основном запросе), но зачем ?
e2.salary > e.salary - а это вот зачем ?
Это условия коррелированного подзапроса, который будет выполняться на второй копии таблицы (обращаю внимание - абсолютно независимой, словно это другая таблица) для каждой записи из первой копии.
То есть подзапрос (вместе с NOT EXISTS) смотрит, есть ли в таблице запись с тем же департаментом, что у текущей записи, и бОльшей зарплатой. Понятно, что для любой записи, где зарплата не максимальна, такая запись найдётся, NOT EXISTS вернёт FALSE, и запись не будет возвращена. А для той записи, где зарплата максимальна, записи с ещё бОльшей зарплатой не найдётся, NOT EXISTS вернёт TRUE, и запрос вернёт эту запись.