Ответ
Подзапрос (вложенный запрос) — это запрос, встроенный в другой SQL-запрос. Они классифицируются по месту использования и зависимости от внешнего запроса.
1. По месту использования:
- В
WHERE/HAVING(для фильтрации):-- Некоррелированный подзапрос (выполняется один раз) SELECT * FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
-- С оператором IN SELECT * FROM products WHERE category_id IN (SELECT id FROM categories WHERE is_active = 1);
-- С оператором EXISTS (часто с корреляцией) SELECT * FROM departments d WHERE EXISTS ( SELECT 1 FROM employees e WHERE e.department_id = d.id AND e.salary > 100000 );
* **В `FROM` (как производная таблица):**
```sql
SELECT dept_name, avg_sal
FROM (
SELECT d.name as dept_name, AVG(e.salary) as avg_sal
FROM departments d
JOIN employees e ON d.id = e.department_id
GROUP BY d.name
) AS department_stats
WHERE avg_sal > 70000;
- В
SELECT(как скалярное выражение):SELECT name, (SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.id) as order_count FROM customers c;
2. По зависимости от внешнего запроса:
-
Коррелированный подзапрос: Зависит от строк внешнего запроса, выполняется для каждой строки. Может быть медленным.
SELECT e1.name, e1.salary FROM employees e1 WHERE salary > ( SELECT AVG(e2.salary) FROM employees e2 WHERE e2.department_id = e1.department_id -- Корреляция! ); -
Некоррелированный подзапрос: Выполняется независимо один раз, результат подставляется во внешний запрос.
Ключевые моменты:
- Подзапросы в
SELECTдолжны возвращать одно значение (скаляр). - Подзапросы в
FROMдолжны иметь алиас. - Часто подзапросы можно переписать на
JOIN, что может быть эффективнее с точки зрения производительности. EXISTSобычно работает быстрееINдля больших наборов данных, особенно с коррелированными подзапросами.
Ответ 18+ 🔞
Да ты посмотри, какие извращения эти SQL-запросы вытворять позволяют! Один запрос в другом, как матрёшка, блядь. Сейчас разберём эту хуйню, чтобы не путаться.
Ну вот смотри, подзапрос — это когда ты один запрос внутрь другого, сука, засовываешь. Как он там живёт и где торчит, от этого и пляшем.
1. Где эту падлу можно пристроить:
- В
WHEREилиHAVING(чтобы отфильтровать по-серьёзному):-- Некоррелированный, то есть независимый чувак. Выполнился разок и всё. SELECT * FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
-- С оператором IN — «найди мне тех, кто в этой толпе» SELECT * FROM products WHERE category_id IN (SELECT id FROM categories WHERE is_active = 1);
-- С оператором EXISTS (тут часто начинается зависимость, коррреляция, блядь) SELECT * FROM departments d WHERE EXISTS ( SELECT 1 FROM employees e WHERE e.department_id = d.id AND e.salary > 100000 );
* **В `FROM` (как будто целая новая таблица из воздуха):**
```sql
SELECT dept_name, avg_sal
FROM (
SELECT d.name as dept_name, AVG(e.salary) as avg_sal
FROM departments d
JOIN employees e ON d.id = e.department_id
GROUP BY d.name
) AS department_stats -- Смотри, алиас ОБЯЗАТЕЛЕН, иначе SQL-сервер охуеет!
WHERE avg_sal > 70000;
- В
SELECT(чтобы в каждой строке своя циферка всплыла):SELECT name, (SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.id) as order_count FROM customers c;
2. А теперь главное — насколько он привязан к внешнему миру:
-
Коррелированный подзапрос: Это самый дотошный, блядь. Он как пиявка — для КАЖДОЙ строки внешней таблицы запускается заново и спрашивает: «А что там по моим условиям?». Может запросто всю производительность в пизду угробить, если таблицы большие.
SELECT e1.name, e1.salary FROM employees e1 WHERE salary > ( SELECT AVG(e2.salary) FROM employees e2 WHERE e2.department_id = e1.department_id -- Вот она, сука, связь! e1.department_id ); -
Некоррелированный подзапрос: Самодостаточный мужик. Отщёлкнулся один раз в начале, получил результат (одно значение или список) и отдал его главному запросу. Дальше пусть тот сам разбирается.
Важные нюансы, а то наебёшься:
- Если пишешь подзапрос в
SELECT— он должен вернуть ОДНУ штуку, одно значение. Не два, не три, а ровно одну циферку или строчку. Иначе будет пиздец и ошибка. - Подзапрос в
FROM— всегда давай ему погоняло, алиас.AS department_stats,AS tmp— как угодно, но дай! - Часто эту всю хуйню можно переписать на обычные
JOIN'ы. И знаешь что?JOIN'ы часто работают быстрее, ёпта! Особенно если оптимизатор запросов тупой. - Запомни назубок:
EXISTSобычно шустрее, чемIN, когда данных — овердохуища. Особенно если подзапрос коррелированный. Он не перебирает всё подряд, а нашел одно совпадение — и сразу «окей, есть!», дальше можно не искать.