Подзапросы: скалярные, IN, EXISTS и коррелированные
Запрос внутри запроса - ответьте на один вопрос, чтобы помочь ответить на больший
Главная идея: Подзапрос - это полноценный
SELECT, записанный внутри другого оператора. Внешний запрос использует то, что возвращает внутренний: одно значение, список значений или просто ответ "да/нет" на вопрос "существует ли хоть одна подходящая строка?". Освоив четыре формы (скалярный, IN, EXISTS и коррелированный), вы сможете выразить вопросы, которые одному плоскому запросу не под силу.
К концу вы сможете:
- писать скалярные подзапросы в
WHEREиSELECT, - использовать подзапрос в
FROMкак производную таблицу, - фильтровать через
INи знать важную ловушкуNOT IN+ NULL, - проверять существование через
EXISTS/NOT EXISTS, - распознавать коррелированный подзапрос и рассуждать о его стоимости,
- переписывать многие подзапросы как соединения и знать, когда это нужно.
1. Наша учебная база данных магазина
Все запросы ниже выполняются над одной небольшой схемой интернет-магазина. Прочитайте три таблицы один раз сейчас; мы будем использовать их на протяжении всей темы.
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(50),
city VARCHAR(50)
);
CREATE TABLE products (
product_id INT PRIMARY KEY,
name VARCHAR(50),
price DECIMAL(8,2)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
product_id INT,
quantity INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
INSERT INTO customers VALUES
(1,'Alice','London'), (2,'Bob','Paris'),
(3,'Carol','London'), (4,'Dan','Berlin');
INSERT INTO products VALUES
(1,'Keyboard',45.00), (2,'Mouse',25.00),
(3,'Monitor',220.00), (4,'Webcam',60.00);
INSERT INTO orders VALUES
(1,1,3,1,'2026-01-05'), (2,1,2,2,'2026-01-06'),
(3,2,1,1,'2026-02-10'), (4,3,3,1,'2026-02-11'),
(5,3,4,1,'2026-03-01');
Обратите внимание на два факта, которые делают примеры интересными: Dan (клиент 4) не сделал ни одного заказа, а Monitor (товар 3) - самый дорогой товар. Вот исходная таблица orders:
| order_id | customer_id | product_id | quantity | order_date |
|---|---|---|---|---|
| 1 | 1 | 3 | 1 | 2026-01-05 |
| 2 | 1 | 2 | 2 | 2026-01-06 |
| 3 | 2 | 1 | 1 | 2026-02-10 |
| 4 | 3 | 3 | 1 | 2026-02-11 |
| 5 | 3 | 4 | 1 | 2026-03-01 |