# Подзапросы (SubQuery) в MySQL:

**Подзапрос** — это SQL-запрос, вложенный внутрь другого SQL-запроса. 

Он может использоваться в операторе `SELECT`, `INSERT`, `UPDATE` или `DELETE`,   
а также в выражениях `WHERE`, `FROM` и `HAVING`.

Пример подзапроса:
```
-- Найти имена сотрудников, работающих в отделе Продаж

SELECT name
FROM employees
WHERE department_id = (
    SELECT id
    FROM departments
    WHERE name = 'Sales'
);
```
В этом примере подзапрос сначала находит id отдела `Sales`, а затем внешний запрос ищет всех сотрудников этого отдела.

## Где можно использовать подзапросы (SubQuery)?

| Место использования | Пример                                                                                                                                                                     | Описание                                                                       |
|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------|
| SELECT              | `SELECT name, salary,` <br> `(SELECT AVG(salary) FROM employes)` <br> ` AS avg_salary FROM employees;`                                                                              | Подзапрос возвращает скалярное значение, используется как поле в SELECT.       |
| FROM                | `SELECT * ` <br> `FROM (SELECT * FROM orders WHERE amount > 100) AS t_big_orders;`                                                                                                 | Подзапрос используется как временная таблица. Требуется псевдоним.             |
| WHERE               | `SELECT name, salary` <br> `FROM employes ` <br> `WHERE employes > (SELECT AVG(salary) FROM employes);`                                                                                   | Подзапрос используется как фильтр — одно из самых распространённых применений. |
| HAVING              | `SELECT customer_id, COUNT(*) ` <br> `FROM orders ` <br> `GROUP BY customer_id ` <br> `HAVING COUNT(*) > (` <br> &nbsp;&nbsp;&nbsp;`SELECT AVG(cnt) ` <br> &nbsp;&nbsp;&nbsp;`FROM (` <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`SELECT COUNT(*) AS cnt ` <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`FROM orders ` <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`GROUP BY customer_id) AS sub` <br>`);` | Подзапрос используется для фильтрации агрегатных значений.                     |


## Градация подзапросов по возвращаемому значению

| Тип подзапроса         | Описание                                            | Где применяется               |
|------------------------|-----------------------------------------------------|-------------------------------|
| Скалярный              | Возвращает одно значение                            | `SELECT`, `WHERE`, `HAVING`   |
| Список значений        | Один столбец (массив)                               | `IN`, `NOT IN`                |
| Множественные значения | Несколько столбцов и строк, сравниваются как списки | `WHERE (col1, col2) IN (...)` |
| Табличный              | Полноценная таблица, используется как временная     | `FROM`, `JOIN`, `WITH`        |

### Примеры 
#### 🟩 Скалярный подзапрос
```
SELECT name
FROM customers
WHERE id = (
    SELECT MIN(id)
    FROM customers
);
```

#### 🟦 Список значений
```
SELECT name
FROM customers
WHERE id IN (
    SELECT customer_id
    FROM orders
);
```

#### 🟨 Множественные значения
```
SELECT *
FROM employees
WHERE (department_id, job_title) IN (
    SELECT dept_id, title
    FROM department_roles
);
```

#### 🟪 Табличный подзапрос
```
SELECT d.name, COUNT(*) AS employee_count
FROM (
    SELECT * FROM employees
    WHERE hired_date >= '2020-01-01'
) AS recent_hires
JOIN departments d ON recent_hires.department_id = d.id
GROUP BY d.name;
```

## ✅ Плюсы подзапросов

| Плюс                 | Объяснение |
|----------------------|------------|
| Читаемость           | Упрощает структуру запроса, особенно при вложенной логике. |
| Инкапсуляция         | Изолирует отдельную часть логики в виде "чёрного ящика". |
| Гибкость             | Позволяет выполнять динамические вычисления и фильтрацию. |
| Без временных таблиц | Не требует отдельного представления или временной таблицы. |

## ❌ Минусы подзапросов

| Минус                        | Объяснение |
|-----------------------------|------------|
| Медленнее JOIN              | Часто `JOIN` работает быстрее, особенно при наличии индексов. |
| Коррелированные подзапросы | Выполняются для каждой строки внешнего запроса — это дорого по ресурсам. |
| Плохо читаемые вложенности | Сложные подзапросы трудны для отладки и понимания. |
| Ограничения MySQL           | В некоторых случаях MySQL накладывает ограничения на использование подзапросов (особенно в старых версиях). |

