Какие типы подзапросов (subqueries) в SQL вы знаете?

Ответ

Подзапрос (вложенный запрос) — это запрос, встроенный в другой 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, когда данных — овердохуища. Особенно если подзапрос коррелированный. Он не перебирает всё подряд, а нашел одно совпадение — и сразу «окей, есть!», дальше можно не искать.