Давай ще глибше зануримось у кролячу нору: розглянемо, як використовувати підзапити в конструкції FROM. Це один із найчастіших підходів у SQL, бо дозволяє створювати потужні тимчасові таблиці прямо "на місці" і переюзати їх, ніби вони реально існують у базі.
Уяви, ти збираєш звіт, який вимагає розрахунків, групувань чи фільтрації даних, але не хочеш створювати додаткові тимчасові таблиці на сервері. Що робити? Ось тут і виручають підзапити у FROM. Вони дають змогу:
- Тимчасово об'єднувати дані або агрегувати їх перед основним запитом.
- Створювати структуровані набори даних "на льоту".
- Зменшити кількість операцій, вимагаючи від бази мінімального збереження проміжних даних.
Підзапити у FROM працюють як міні-таблиці, які ти можеш юзати в основному запиті. Це схоже на збірку модульного конструктора: швидко, гнучко і без зайвих заморочок :)
Базові речі про підзапити у FROM
У підзапитах у FROM ми створюємо тимчасову таблицю (або підтаблицю), яка стає частиною загального запиту. Для цього треба зробити три ключові кроки:
- Написати підзапит у конструкцію
FROMу круглих дужках. - Дати аліас (псевдонім) підзапиту.
- Використовувати цей псевдонім, як повноцінну таблицю.
Синтаксис
SELECT колонки
FROM (
SELECT колонки
FROM таблиця
WHERE умова
) AS псевдонім
WHERE зовнішня_умова;
Звучить трохи страшно? Давай до прикладів.
Приклад: Студенти і середній бал
Припустимо, у нас є дві таблиці:
students (дані про студентів — їх ім'я та ID):
| student_id | student_name |
|---|---|
| 1 | Alex |
| 2 | Anna |
| 3 | Dan |
grades (дані про оцінки студентів):
| grade_id | student_id | grade |
|---|---|---|
| 1 | 1 | 80 |
| 2 | 1 | 85 |
| 3 | 2 | 90 |
| 4 | 3 | 70 |
| 5 | 3 | 75 |
Тепер задача: отримати список студентів і їхній середній бал.
Можемо почати з простого підзапиту, який рахує середній бал кожного студента, а потім використати його в основному запиті.
SELECT s.student_name, g.avg_grade
FROM (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g
JOIN students AS s ON s.student_id = g.student_id;
Результат:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
| Dan | 72.5 |
Тимчасові таблиці "на льоту"
Підзапити у FROM особливо корисні, коли треба зробити більше одного рівня обробки даних. Наприклад, якщо хочеш не просто отримати середній бал, а й порахувати максимальний бал для кожного студента — все в одному запиті.
SELECT g.student_id, g.avg_grade, g.max_grade
FROM (
SELECT student_id,
AVG(grade) AS avg_grade,
MAX(grade) AS max_grade
FROM grades
GROUP BY student_id
) AS g;
Результат:
| student_id | avg_grade | max_grade |
|---|---|---|
| 1 | 82.5 | 85 |
| 2 | 90 | 90 |
| 3 | 72.5 | 75 |
Зверни увагу, що це працює як повноцінна тимчасова таблиця зі своїми аналогами стовпців: avg_grade і max_grade.
Коли підзапити у FROM найкраще використовувати?
Для агрегованих даних. Якщо хочеш спочатку зробити підрахунки (наприклад, порахувати середнє, суми чи максимуми), а потім об'єднати результати з іншими таблицями.
Для фільтрації даних. Коли треба відфільтрувати дані до об'єднання з основною таблицею.
Для спрощення складних запитів. Розділення складних задач на етапи допомагає уникнути плутанини.
Приклад: Звіт про студентів з двома рівнями обробки
Уявімо, що хочемо знайти студентів, у яких середній бал більше 80. Почнемо з підзапиту, який рахує середні бали, і потім використаємо його у фільтрі.
SELECT s.student_name, g.avg_grade
FROM students AS s
JOIN (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g ON s.student_id = g.student_id
WHERE g.avg_grade > 80;
Результат:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
Особливості використання та поради
Обов'язковий псевдонім. Завжди давай аліас підзапиту (наприклад, AS g), інакше PostgreSQL не зрозуміє, як звертатись до цієї "тимчасової таблиці".
Оптимізація. Підзапити у FROM можуть бути повільніші за об'єднання таблиць (JOIN), особливо якщо ти фільтруєш дані всередині підзапиту.
Індексація. Переконайся, що поля для об'єднання, індекси і фільтри оптимізовані — це дуже впливає на швидкість.
Приклад складного запиту: курси і кількість студентів
Тепер давай зробимо реальну задачу складніше. Уяви, що є така таблиця:
courses (список курсів):
| course_id | course_name |
|---|---|
| 1 | SQL Basics |
| 2 | Python Basics |
І enrollments (записи студентів на курси):
| student_id | course_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
Тепер хочемо дізнатись, скільки студентів записано на кожен курс.
SELECT c.course_name, e.students_count
FROM courses AS c
JOIN (
SELECT course_id, COUNT(student_id) AS students_count
FROM enrollments
GROUP BY course_id
) AS e ON c.course_id = e.course_id;
Результат:
| course_name | students_count |
|---|---|
| SQL Basics | 2 |
| Python Basics | 1 |
Сподіваюсь, лекція тобі зайшла... але наступна буде ще цікавіша :)
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ