Вложенный запрос MySQL полное руководство с примерами

Вложенный запрос MySQL полное руководство с примерами

Вложенный запрос MySQL (subquery) — это SQL-запрос внутри другого запроса. Вложенные запросы MySQL используются для получения данных, которые затем применяются в основном запросе.

В этой статье разберем:

Что такое вложенный запрос MySQL

Вложенный запрос MySQL — это запрос внутри другого SQL запроса.

Общий синтаксис:

SELECT column_name
FROM table_name
WHERE column_name = (
    SELECT column_name
    FROM table_name
);

Внутренний запрос выполняется первым, затем результат передается во внешний запрос.

Пример таблиц для вложенных запросов

Допустим, у нас есть таблицы:

Таблица users:

id | name | role_id
1  | Ivan | 1
2  | Alex | 2
3  | Oleg | 1

Таблица roles:

id | role_name
1  | admin
2  | user

Простой вложенный запрос MySQL

Найти всех администраторов:

SELECT *
FROM users
WHERE role_id = (
    SELECT id
    FROM roles
    WHERE role_name = 'admin'
);

Как работает:

  • Внутренний запрос находит id роли admin
  • Внешний запрос получает пользователей с этим id

Вложенный запрос MySQL в WHERE

Самый популярный вариант использования вложенного запроса — в WHERE. Но чаще всего вы не будете писать вручную искомый текст, а будете подставлять какую либо переменную. По этой теме мы уже писали в одной из прошлой статье, о том, что такое mysql инъекция и как защитить сайт.

Пример:

SELECT *
FROM products
WHERE category_id = (
    SELECT id
    FROM categories
    WHERE name = 'Ноутбуки'
);

Этот запрос:

  • Получает ID категории
  • Находит товары в этой категории

Вложенный запрос MySQL с IN

Если вложенный запрос возвращает несколько значений, используется IN:

SELECT *
FROM users
WHERE role_id IN (
    SELECT id
    FROM roles
    WHERE role_name IN ('admin', 'manager')
);

Этот запрос найдет:

  • Администраторов
  • Менеджеров

Вложенный запрос MySQL с NOT IN

Можно исключить данные:

SELECT *
FROM users
WHERE role_id NOT IN (
    SELECT id
    FROM roles
    WHERE role_name = 'admin'
);

Этот запрос вернет всех пользователей кроме администраторов.

Вложенный запрос MySQL в SELECT

Вложенные запросы можно использовать в SELECT.

Пример:

SELECT 
name,
(
    SELECT role_name
    FROM roles
    WHERE roles.id = users.role_id
) AS role
FROM users;

Результат:

Ivan | admin
Alex | user
Oleg | admin

Вложенный запрос MySQL в FROM

Вложенный запрос можно использовать как временную таблицу.

Пример:

SELECT *
FROM (
    SELECT *
    FROM users
    WHERE role_id = 1
) AS admins;

Этот запрос:

  • Создает временную таблицу
  • Затем выполняет запрос к ней

Вложенный запрос MySQL с EXISTS

EXISTS проверяет наличие записей.

Пример:

SELECT *
FROM users
WHERE EXISTS (
    SELECT *
    FROM orders
    WHERE orders.user_id = users.id
);

Этот вложенный запрос:

  • Найдет пользователей
  • У которых есть заказы

Пример с NOT EXISTS:

SELECT *
FROM users
WHERE NOT EXISTS (
    SELECT *
    FROM orders
    WHERE orders.user_id = users.id
);

Этот запрос найдет пользователей без заказов.

Коррелированный вложенный запрос MySQL

Коррелированный запрос зависит от внешнего запроса.

Пример:

SELECT *
FROM users u
WHERE salary > (
    SELECT AVG(salary)
    FROM users
    WHERE department_id = u.department_id
);

Этот запрос:

  • Сравнивает зарплату
  • С средней зарплатой отдела

Вложенный запрос MySQL с агрегатными функциями

Пример, найти пользователей с максимальной зарплатой:

SELECT *
FROM users
WHERE salary = (
    SELECT MAX(salary)
    FROM users
);

Вложенный запрос MySQL с COUNT

Этот запрос найдет пользователей с более чем 5 заказами

SELECT *
FROM users
WHERE id IN (
    SELECT user_id
    FROM orders
    GROUP BY user_id
    HAVING COUNT(*) > 5
);

Вложенный запрос MySQL с JOIN

Иногда вложенные запросы заменяются JOIN. Вложенный запрос:

SELECT *
FROM users
WHERE role_id = (
    SELECT id
    FROM roles
    WHERE role_name = 'admin'
);

А теперь через JOIN:

SELECT users.*
FROM users
JOIN roles ON users.role_id = roles.id
WHERE roles.role_name = 'admin';

JOIN часто работает быстрее.

Вложенные запросы MySQL UPDATE/DELETE/INSERT

Вложенные запросы в mysql можно применять не только для получения информации, но и в других случаях при манипуляции с данными. Подобные действия не всегда имеют место быть в разработке, но для информации будет полезным.

Вложенный запрос MySQL UPDATE

Можно использовать вложенный запрос mysql при обновлении данных:

UPDATE users
SET role_id = (
    SELECT id
    FROM roles
    WHERE role_name = 'manager'
)
WHERE name = 'Ivan';

Вложенный запрос MySQL DELETE

Например, можно произвести удаление пользователя с вложенным запросом mysql:

DELETE FROM users
WHERE id IN (
    SELECT user_id
    FROM banned_users
);

Вложенный запрос MySQL INSERT

Пример вложенного запроса через insert:

INSERT INTO archive_users
SELECT *
FROM users
WHERE id IN (
    SELECT user_id
    FROM old_users
);

Оптимизация вложенных запросов MySQL

Ранее мы уже писали в одной из статей про mysql оптимизацию запросов и ускорение работы. Некоторые советы по использованию вложенных запросов:

  • Используйте индексы
  • Избегайте вложенных запросов в больших таблицах
  • Используйте JOIN при необходимости
  • Ограничивайте результат LIMIT

Пример такого запроса:

SELECT *
FROM users
WHERE id = (
    SELECT user_id
    FROM orders
    LIMIT 1
);

Вложенный запрос MySQL — это мощный инструмент для работы с данными. Он позволяет создавать сложные SQL запросы, фильтровать данные и выполнять аналитику.
Основные типы вложенных запросов:

  • WHERE
  • SELECT
  • FROM
  • EXISTS
  • UPDATE
  • DELETE

Есть еще более интересные вариации запросов, о них мы писали в одной из статей: mysql select запросы DISTINCT, GROUP, LIKE, UNION. Используйте вложенные запросы MySQL для гибкой работы с базой данных и оптимизации SQL запросов.