Перейти до основного вмісту
Модуль 4 · Урок 4 із 416/57 у курсі~12 min
Модульні уроки (4/4)

Запит всередині іншого: підзапити

Ви навчилися видобувати, фільтрувати, групувати, об’єднувати та перетворювати. Там остання фундаментальна ідея: помістити запит в інший. Це називаються підзапити, і вони є кроком, який дозволяє відповісти на запитання наприклад "хто заробляє вище середнього?" або "у яких відділах є хтось призначено для проекту?".

Основний синтаксис

Підзапит — це SELECT, взятий у круглі дужки, який використовується замість одного значення або список значень в іншому запиті:

SQL
-- Find who earns MORE THAN THE COMPANY AVERAGE:
SELECT first_name, last_name, salary
FROM   employees
WHERE  salary > (SELECT AVG(salary) FROM employees);

Механізм спочатку виконує підзапит — SELECT AVG(salary) FROM employees повертає єдине число — і потім використовує це число у зовнішньому WHERE ніби ви це від руки написали. Саме в цьому й полягає перевага: ви робите не потрібно знати середнє значення заздалегідь, SQL обчислює його за вас.

Три найпоширеніші «типи»

1. Підзапит повертає одне значення

Приклад вище: підзапит створює один рядок, один стовпець (наз скаляр). Ви використовуєте його з =, >, < тощо.

SQL
-- Employee with the highest salary:
SELECT first_name, last_name
FROM   employees
WHERE  salary = (SELECT MAX(salary) FROM employees);

2. Підзапит повертає список

Підзапит створює один стовпець, багато рядків. Ви використовуєте його з IN (...):

SQL
-- Departments that have at least one employee:
SELECT name
FROM   departments
WHERE  id IN (SELECT DISTINCT department_id
              FROM employees
              WHERE department_id IS NOT NULL);

3. Підзапит як "таблиця" (FROM)

Підзапит також може зайняти місце таблиці в FROM. Це корисно для попередньо обчислити агрегати, а потім відфільтрувати або об’єднати їх:

SQL
-- Departments with average salary above 40000:
SELECT d.name, medie.stipendio_medio
FROM   departments AS d
JOIN  (SELECT department_id, AVG(salary) AS stipendio_medio
       FROM employees
       GROUP BY department_id) AS medie
   ON d.id = medie.department_id
WHERE  medie.stipendio_medio > 40000;

Підзапит чи JOIN? Коли використовувати який

Часто той самий результат можна отримати за допомогою JOIN або за допомогою підзапиту. Емпіричне правило:

  • Щоб фільтрувати рядки однієї таблиці на основі властивості іншої ("співробітники, чиї відділи…"), IN (subquery) дуже читабельний.
  • Щоб об’єднати стовпці з кількох таблиць у результат, використовуйте JOIN.
  • Щоб обчислити агрегат і використовувати його як порогове значення ("вище середній"), скалярний підзапит є природним вибором.

На практиці ви побачите обидва: механізм SQL часто оптимізує їх однаково спосіб. Виберіть форму, яка найкраще читається.

Спробуйте

вправи#sql.m4.l4.e1
Спроби: 0Завантаження…

Знайдіть ім’я (first_name), прізвище (last_name) і зарплату (salary) працівників, які заробляють СТРОГО більше, ніж у середньому по компанії. Три колони.

Завантаження редактора…
Показати підказку

Замінити ? із підзапитом SELECT AVG(salary) FROM співробітників — повертає єдине число, яке використовується як порогове значення.

Рішення доступне після 3 спроб

Повторна вправа

вправи#sql.m4.l4.e2
Спроби: 0Завантаження…

Перелічіть назви (departments.name) відділів, у яких є принаймні один співробітник із зарплатою, що перевищує 50 000. Використовуйте підзапит із IN. Порядок за алфавітом.

Завантаження редактора…
Показати підказку

Внутрішній підзапит повертає ідентифікатори відділів, у яких є співробітники із зарплатою > 50 000. Потім WHERE id IN (...) у зовнішньому запиті.

Рішення доступне після 3 спроб