JavaRush/Курсы/Модуль 4. Работа с БД/Подзапросы с таблицами

Подзапросы с таблицами

Открыта

Подзапрос возвращает таблицу

И наконец третий вариант – когда подзапрос возвращает целую таблицу. Это самый распространенный вариант.

Очень часто возникают ситуации, когда мы хотим немного подправить определенную таблицу. И только потом объединить (посредством оператора JOIN ON) исправленную таблицу с другой.

Давай для начала возьмет самый простой случай, где мы объединяли две таблицы посредством JOIN:

SELECT * FROM employee e JOIN task t ON e.id = t.emploee_id

И как ты, наверное, помнишь, в таблице task есть задачи, которые ни на кого не назначены: employee_id равно NULL.

Давай сгенерируем исправленную таблицу, где все повисшие задачи назначим на директора (его ID = 4).

Для этого воспользуемся функцией IFNULL():

SELECT id, IFNULL(employee_id, 4) AS employee_id, name, deadline FROM task 

И результат такого запроса:

id employee_id name deadline
1 1 Исправить багу на фронтенде 2022-06-01
2 2 Исправить багу на бэкенде 2022-06-15
3 5 Купить кофе 2022-07-01
4 5 Купить кофе 2022-08-01
5 5 Купить кофе 2022-09-01
6 4 Убрать офис (NULL)
7 4 Наслаждаться жизнью (NULL)
8 6 Наслаждаться жизнью (NULL)

Красным цветом отмечена исправленная ячейка.

Теперь давай подставим нашу исправленную таблицу в запрос:

SELECT * FROM employee e JOIN task t ON e.id = t.emploee_id

Вместо таблицы task.

Выглядеть такой запрос будет примерно так:

SELECT * FROM employee e JOIN (  SELECT id, IFNULL(employee_id, 4) AS employee_id, name, deadline FROM task ) t ON e.id = t.emploee_id

Мы вместо слова task написали круглые скобочки и в них поместили тело запроса.

Кстати, псевдоним t (алиас) для вложенного запроса очень пригодился. У вложенного запроса в отличии от таблицы имени своего нет, поэтому псевдоним очень даже к месту.

И вот результат такого запроса:

id name occupation salary age join_date id employee_id name
1 Иванов Иван Программист 100000 25 2012-06-30 1 1 Исправить багу на фронтенде
2 Петров Петр Программист 80000 23 2013-08-12 2 2 Исправить багу на бэкенде
4 Рабинович Мойша Директор 200000 35 2015-05-12 6 4 Убрать офис
4 Рабинович Мойша Директор 200000 35 2015-05-12 7 4 Наслаждаться жизнью
5 Кириенко Анастасия Офис-менеджер 40000 25 2015-10-10 4 5 Купить кофе
5 Кириенко Анастасия Офис-менеджер 40000 25 2015-10-10 5 5 Купить кофе
5 Кириенко Анастасия Офис-менеджер 40000 25 2015-10-10 3 5 Купить кофе
6 Васька кот 1000 3 2018-11-11 8 6 Наслаждаться жизнью

На нашем директоре висит задача “убрать офис”, думаю, он быстро найдет, кому ее делегировать :)

Использование оператора WITH

Кстати, начиная с 8-й версии MySQL ты больше не обязан засовывать все свои подзапросы прямо внутрь финального запроса. Их можно выполнять отдельно. Для этого используется оператор WITH.

Он позволяет создать виртуальную таблицу (поименованный запрос) и его вид задается шаблоном:

WITH имя AS (запрос) 

Часто бывают ситуации, когда в вашем подзапросе есть колонки без имени, например такие как COUNT(*), которым ты не назначил уникальное имя. На этот случай у оператора WITH существует возможность указать новые имена колонок для подзапроса.

Второй его вид задается шаблоном:

WITH имя(колонка1, колонка2, …) AS (запрос) 

Ты можешь использовать сколько угодно виртуальных таблиц (поименованных запросов) и ссылаться в них друг на друга. Общий вид твоего запроса будет иметь примерно такой формат:

WITH имя1 AS (запрос1), имя2 AS (запрос2), имя3 AS (запрос3) SELECT * FROM имя1 JOIN имя2 ON … 

Теперь давай возьмем наш страшный запрос:

SELECT * FROM employee e JOIN ( SELECT id, IFNULL(employee_id, 4) AS employee_id, name, deadline  FROM task ) t ON e.id = t.emploee_id  

И перепишем его с использованием оператора WITH:

WITH task2(id, employee_id, name, deadline) AS (SELECT id, IFNULL(employee_id, 4), name, deadline FROM task) SELECT * FROM employee e JOIN task2 t ON e.id = t.emploee_id

Или можно без имен колонок, но тогда придется обязательно указывать алиас для функции IFNULL():

WITH task2 AS ( SELECT id, IFNULL(employee_id, 4) AS employee_id, name, deadline FROM task ) SELECT * FROM employee e JOIN task2 t ON e.id = t.emploee_id 
1
Задача
Модуль 4. Работа с БД,  3 уровень,  5 лекция
Недоступна
LEFT JOIN с подзапросом
LEFT JOIN с подзапросом
1
Задача
Модуль 4. Работа с БД,  3 уровень,  5 лекция
Недоступна
Все любят Спилберга
Все любят Спилберга
1
Задача
Модуль 4. Работа с БД,  3 уровень,  5 лекция
Недоступна
Подзапрос и множественные фильтры
Подзапрос и множественные фильтры
1
Задача
Модуль 4. Работа с БД,  3 уровень,  5 лекция
Недоступна
Для тех, кто любит sci-fi
Для тех, кто любит sci-fi
1
Задача
Модуль 4. Работа с БД,  3 уровень,  5 лекция
Недоступна
Подзапросы, фильтры и ограничение
Подзапросы, фильтры и ограничение
1
Задача
Модуль 4. Работа с БД,  3 уровень,  5 лекция
Недоступна
Оператор WITH
Оператор WITH
1
Задача
Модуль 4. Работа с БД,  3 уровень,  5 лекция
Недоступна
WITH с дополнительным условием
WITH с дополнительным условием
1
Задача
Модуль 4. Работа с БД,  3 уровень,  5 лекция
Недоступна
WITH с дополнительным условием - 2
WITH с дополнительным условием - 2
Комментарии (20)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Анастасия
Уровень 93
8 января, 12:16
Не очень удобно читать сплошную строку с запросом и с прогруткой. Приходится туда-сюда крутить чтобы вникнуть. Было бы классно, если это переработали, можно же писать запрос с переносом строки =(
Егор
Уровень 107
25 ноября 2025, 11:29
film напоминает конкретный жест рукой в положении кулака
Александр
Уровень 1
14 января 2025, 09:04
к последней задаче, вроде так группировать нельзя, и не правильно, но mySql позволяет видимо) Поведение MySQL: 1. Строгий режим (по умолчанию включен): Если сервер работает в строгом режиме (режимы вроде ONLY_FULL_GROUP_BY включены), то MySQL выдаст ошибку: ERROR 1055 (42000): 'column_name' isn't in GROUP BY Это происходит, потому что в строгом режиме MySQL требует, чтобы: Все столбцы в SELECT, которые не являются частью агрегатной функции, должны быть указаны в GROUP BY. 2. Нестрогий режим: Если сервер работает без строгого режима, то MySQL выбирает произвольное значение для тех столбцов, которые не указаны в GROUP BY. Это может привести к неожиданным результатам. Например: SELECT customer_id, product_id, SUM(amount) FROM sales GROUP BY customer_id; В данном случае: SUM(amount) будет корректно рассчитан. product_id будет взят произвольным образом из одной из строк группы, что может быть некорректно.
Олег
Уровень 106
Expert
19 сентября 2024, 20:03
Лютая жесть.
Александр
Уровень 109
Expert
13 апреля 2024, 14:28
Чтобы прописать несколько временных таблиц в WITH - нужно поставить запятую после указания подзапроса (пригодится в последней задаче)
Радомир
Уровень 106
Expert
11 марта 2024, 03:33
Используя оператор AS, добавить подзапрос, в котором требуется найти SUM колонки grossed таблицы films, при этом назвав её total. По правилам выделенная часть относится к таблице, а не к колонке.
Anonymous #3322801
Уровень 1
Expert
23 октября 2023, 15:27
Этот блок задач надо однозначно дорабатывать, хотя сами задачи меня очень порадовали.
Андрей
Уровень 108
Expert
8 июля 2023, 13:11
как это вяжется с условием в последней задаче?? я всю голову сломал. Нельзя же так группировать?
Андрей
Уровень 108
Expert
8 июля 2023, 13:18
Anonymous #3322801
Уровень 1
Expert
23 октября 2023, 14:47
Тоже заметила, postgres не пропустил такой запрос, что логично.
I'm Siberian Trust me, i'm an engineer Expert
12 января 2025, 14:49
а валидатор с тобой не согласен 😁
hint1k
Уровень 51
9 мая 2023, 15:07
На директоре висит задача “убрать офис”,
он быстро найдет, кому ее делегировать
приказом директора задача "уборка офиса" возложена на сотрудника id = 6
Павел К
Уровень 34
7 апреля 2023, 09:29
На нашем директоре висит задача “убрать офис”, думаю, он быстро найдет, кому ее делегировать :)Использование оператора WITH
По идее, вторая часть должна быть на новой строке и быть заголовком.