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

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

Модуль 4. Работа с БД
3 уровень , 5 лекция
Открыта

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

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

Очень часто возникают ситуации, когда мы хотим немного подправить определенную таблицу. И только потом объединить (посредством оператора 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 лекция
Недоступна
task0343
В данной задаче тебе потребуется: 1. Выбрать колонку full_name из таблицы film_directors. 2. Используя оператор LEFT JOIN, добавить подзапрос, в котором требуется выбрать колонку title таблицы films, с фильтром WHERE, который должен находить только комедии из колонки genre. 3. Таблица films должна б
1
Задача
Модуль 4. Работа с БД, 3 уровень, 5 лекция
Недоступна
task0344
В данной задаче тебе потребуется: 1. Выбрать колонку title из таблицы films. 2. Используя оператор LEFT JOIN, добавить подзапрос, в котором требуется выбрать колонку last_name таблицы film_directors, с фильтром WHERE, который должен находить только 'Spielberg'. 3. Таблица film_directors долж
1
Задача
Модуль 4. Работа с БД, 3 уровень, 5 лекция
Недоступна
task0345
В данной задаче тебе потребуется: 1. Выбрать колонку last_name из таблицы film_directors. 2. Используя оператор LEFT JOIN, добавить подзапрос, в котором требуется выбрать колонку grossed таблицы films, с фильтром WHERE, который должен находить фильмы, которые принесли более 100. 3. Таблица films дол
1
Задача
Модуль 4. Работа с БД, 3 уровень, 5 лекция
Недоступна
task0346
В данной задаче тебе потребуется: 1. Выбрать все колонки из таблицы films. 2. Используя оператор JOIN, добавить подзапрос, в котором требуется выбрать колонку year_born таблицы film_directors, с фильтром WHERE, который должен находить режисёров, которые родились до 1940 года. 3. Таблица film_directo
1
Задача
Модуль 4. Работа с БД, 3 уровень, 5 лекция
Недоступна
task0347
В данной задаче тебе потребуется: 1. Выбрать все колонки из таблицы film_directors. 2. Используя оператор RIGHT JOIN, добавить подзапрос, в котором требуется выбрать колонку title таблицы films, с фильтром WHERE, который должен находить фильмы, которые были выпущены после 1990 года. 3. Таблица films
1
Задача
Модуль 4. Работа с БД, 3 уровень, 5 лекция
Недоступна
task0348
В данной задаче тебе потребуется: 1. Используя оператор WITH создать временную таблицу grossed_total. 2. Используя оператор AS, добавить подзапрос, в котором требуется найти SUM колонки grossed таблицы films, при этом назвав её total. 3. Используя операторы SELECT и AVG найти средний доход у колонки
1
Задача
Модуль 4. Работа с БД, 3 уровень, 5 лекция
Недоступна
task0349
В данной задаче тебе потребуется: 1. Используя оператор WITH создать временную таблицу tempTable с колонкой averageDOB. 2. Используя оператор AS, добавить подзапрос, в котором требуется найти среднее значение колонки year_born таблицы film_directors. 3. Выбрать колонки id, full_name и year_born из т
1
Задача
Модуль 4. Работа с БД, 3 уровень, 5 лекция
Недоступна
task0350
В данной задаче тебе потребуется: 1. Используя оператор WITH создать временную таблицу tempTable с колонкой averageGrossed...
Комментарии (18)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Александр Уровень 109
14 января 2025
к последней задаче, вроде так группировать нельзя, и не правильно, но 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
Лютая жесть.
Александр Уровень 109 Expert
13 апреля 2024
Чтобы прописать несколько временных таблиц в WITH - нужно поставить запятую после указания подзапроса (пригодится в последней задаче)
Радомир Уровень 106 Expert
11 марта 2024
Используя оператор AS, добавить подзапрос, в котором требуется найти SUM колонки grossed таблицы films, при этом назвав её total. По правилам выделенная часть относится к таблице, а не к колонке.
Anonymous #3322801 Уровень 2 Expert
23 октября 2023
Этот блок задач надо однозначно дорабатывать, хотя сами задачи меня очень порадовали.
Андрей Уровень 108 Expert
8 июля 2023
как это вяжется с условием в последней задаче?? я всю голову сломал. Нельзя же так группировать?
Андрей Уровень 108 Expert
8 июля 2023
Anonymous #3322801 Уровень 2 Expert
23 октября 2023
Тоже заметила, postgres не пропустил такой запрос, что логично.
I'm Siberian Уровень 109 Expert
12 января 2025
а валидатор с тобой не согласен 😁
hint1k Уровень 51
9 мая 2023

На директоре висит задача “убрать офис”, 
он быстро найдет, кому ее делегировать
приказом директора задача "уборка офиса" возложена на сотрудника id = 6
Павел К Уровень 34
7 апреля 2023

На нашем директоре висит задача “убрать офис”, думаю, он быстро найдет, кому ее делегировать :)Использование оператора WITH
По идее, вторая часть должна быть на новой строке и быть заголовком.
aDuVaN4Ik Уровень 42
3 января 2023
Можете объяснить строчку SELECT id, IFNULL(employee_id, 4) AS employee_id, name, deadline Не совсем понимаю что к чему.
Марат Гарипов Уровень 108 Expert
3 января 2023
выбираем 4 колонки. одну из них, которой мы присвоили алиас employee_id, посредством функции IFNULL заполняем значениями. если employee_id не является null, то подставляем первый аргумент, если null, то меняем его на 4 повторять и закреплять тут
aDuVaN4Ik Уровень 42
3 января 2023
Спасибо!
Pavel Petrov Уровень 109 Expert
23 декабря 2022
Для лучшего понимания для чего нужен with https://www.youtube.com/watch?v=XpOopycXsk0
zaiats1311 Уровень 41
2 июня 2024
Объяснили доходчивее, чем в лекции