Вложенные запросы в SQL

Язык SQL позволяет вкладывать одни запросы в другие запросы. Это дает возможность написать один очень большой запрос, который будет делать что-то большое и сложное, хотя при этом читабельность кода значительно снижается.

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

  • Подзапрос возвращает одно единственное значение (одна колонка и одна строка).
  • Подзапрос возвращает список значений (таблица с одной колонкой).
  • Подзапрос возвращает таблицу (много колонок, любое количество строк).

Давай разберем по одному примеру для каждого случая.

Подзапрос со скалярным результатом

Давай найдем список всех наших сотрудников из таблицы employee, чья зарплата выше средней по компании. Как нам это сделать?

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

SELECT AVG(salary) FROM employee 

Тогда MySQL вернул нам значение: 76833.3333.

Как теперь найти список всех сотрудников, чья зарплата выше средней? Тоже очень просто:

 SELECT * FROM employee 
   WHERE salary > 76833.3333 

Результат этого запроса будет таким:

id name occupation salary
1 Иванов Иван Программист 100000
2 Петров Петр Программист 80000
4 Рабинович Мойша Директор 200000

А теперь мы просто совместим оба запроса, подставив вместо значения 76833 первый запрос:

   SELECT * FROM employee 
   WHERE salary > (SELECT AVG(salary) FROM employee) 

Результат этого запроса будет таким же:

id name occupation salary
1 Иванов Иван Программист 100000
2 Петров Петр Программист 80000
4 Рабинович Мойша Директор 200000

Подзапрос со списком значений

Помнишь когда-то давно у нас была задача – найти все записи из одной таблицы, для которых нет соответствующих записей из другой?

Там еще была такая картинка:

Если не ошибаюсь, то задание звучит так: отобразите список всех сотрудников из таблицы employee, для которых нет задач в таблице task.

Давай тоже найдем решение в два этапа.

Сначала напишем запрос, который вернет id всех сотрудников, у которых есть задачи в таблице task. Только не забудьте две вещи:

  • убрать дубликаты – используйте ключевое слово DISTINCT.
  • уберите NULL-значения из результата.
SELECT DISTINCT employee_id FROM task 
   WHERE employee_id IS NOT NULL

И вот мы получили красивый результат такого запроса:

employee_id
1
2
5
4
6

Давай для удобства временно запишем его в виде последовательности: 1,2,5,4,6. Теперь напишем второй запрос – к таблице employee, которая вернет нам список сотрудников, чьи id не содержатся в первом списке:

SELECT * FROM employee  
WHERE id NOT IN (1,2,5,4,6)

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

id name occupation salary age join_date
3 Иванов Сергей Тестировщик 40000 30 2014-01-01

А теперь можно, как и в предыдущем примере, совместить оба запроса, просто подставив вместо списка id тело первого запроса.

 SELECT * FROM employee 
   WHERE id NOT IN ( 
      	SELECT DISTINCT employee_id FROM task 
      	WHERE employee_id IS NOT NULL 
   )
undefined
1
Задача
Модуль 4. Работа с БД, 3 уровень, 4 лекция
Недоступна
task0336
1. Выбрать колонку year_born из таблицы authors. 2. Используя оператор WHERE, добавить условие, что year_born таблицы authors должно быть меньше или равно максимальному значению date_released из таблицы books.
undefined
1
Задача
Модуль 4. Работа с БД, 3 уровень, 4 лекция
Недоступна
task0337
1. Выбрать все колонки из таблицы authors. 2. Добавить условие, что колонка id таблицы authors не должна включать в себя автора с author_id 7 (из таблицы books) и с title 'War and Peace'.
undefined
1
Задача
Модуль 4. Работа с БД, 3 уровень, 4 лекция
Недоступна
task0338
1. Выбрать все колонки из таблицы authors. 2. Добавить условие, что колонка full_name не должна (используй NOT LIKE) включать в себя результат подзапроса. 3. В подзапросе, через конкатенацию следует выбрать колонки first_name и last_name таблицы authors, добавив между ними пробел. Затем, дополнительно указать, что
undefined
1
Задача
Модуль 4. Работа с БД, 3 уровень, 4 лекция
Недоступна
task0339
1. Выбрать все колонки из таблицы authors. 2. Используя операторы WHERE и IN, добавить условие, что колонка id должна включать в себя результат подзапроса. 3. В подзапросе следует выбрать колонку author_id таблицы books, затем дополнительно указать, что колонка genre должна содержать только 'fan
undefined
1
Задача
Модуль 4. Работа с БД, 3 уровень, 4 лекция
Недоступна
task0340
1. Выбрать все колонки из таблицы authors. 2. Используя операторы WHERE и NOT IN, добавить условие, что колонка id не должна включать в себя результат подзапроса. 3. В подзапросе следует выбрать колонку author_id таблицы books, затем дополнительно указать, что колонка author_id не должна содержать NULL, и колонка genre (также таблицы books) должна равняться 'novel'.
undefined
1
Задача
Модуль 4. Работа с БД, 3 уровень, 4 лекция
Недоступна
task0341
В данной задаче тебе потребуется: 1. Выбрать все колонки из таблицы films. 2. Используя операторы WHERE и LIKE, добавить условие, что колонка title должна включать в себя результат подзапроса. 3. В подзапросе следует выбрать колонку title таблицы films, затем дополнительно указать, что колонка title
undefined
1
Задача
Модуль 4. Работа с БД, 3 уровень, 4 лекция
Недоступна
task0342
В данной задаче тебе потребуется: 1. Выбрать все колонки из таблицы film_directors. 2. Используя операторы WHERE, LIKE и CONCAT, добавить условие, что колонка full_name должна включать в себя результат подзапроса. 3. В подзапросе следует выбрать две колонки, first_name и last_name (таблицы film_dire