JavaRush /Курси /SQL SELF /Використання SELECT всередині SELECT...

Використання SELECT всередині SELECT

SQL SELF
Рівень 13 , Лекція 1
Відкрита

Уяви, що ти працюєш аналітиком в університеті (ми ж робимо базу даних для університету, пам’ятаєш?). Тебе попросили не просто вивести студентів і їхні оцінки, а додати в таблицю стовпець з максимальною оцінкою в групі, щоб легко порівнювати результати. Як вирішити цю задачу? Звісно, за допомогою підзапитів у SELECT!

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

Основи вкладених запитів у SELECT

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

Ось простий приклад. Припустимо, у нас є таблиця students з такою структурою:

student_id name group_id
1 Linda 101
2 Otto 102
3 Anna 101

І таблиця grades:

grade_id student_id grade
1 1 5
2 1 4
3 2 3
4 3 5
5 3 4

Приклад 1: Додавання максимальної оцінки в групі

Задача: вивести імена студентів, їхні оцінки та максимальну оцінку в групі, щоб було видно, наскільки оцінки кожного студента відрізняються від кращих результатів групи.

SQL-код:

SELECT
    s.name AS student_name,
    g.grade AS student_grade,
    (
        SELECT MAX(grade) -- цей запит повертає одне єдине значення 
        FROM grades 
        INNER JOIN students ON grades.student_id = students.student_id
        WHERE students.group_id = s.group_id
    ) AS max_group_grade 
FROM 
    students s
INNER JOIN 
    grades g ON s.student_id = g.student_id;

Що тут відбувається:

  1. Для кожного студента ми отримуємо його ім’я та оцінку (s.name, g.grade).
  2. SELECT MAX(grade) — це підзапит, який повертає максимальну оцінку всередині групи студента.
  3. Підзапит виконується для кожного рядка основного запиту й використовує умову WHERE students.group_id = s.group_id, щоб обмежити вибірку однією групою.

Приклад 2: Середня оцінка по групі

Хочеш бути ще кориснішим для аналітиків? Додамо у вивід не тільки максимальну оцінку, а й середню оцінку по групі.

SQL-код:

SELECT
    s.name AS student_name,
    g.grade AS student_grade,
    (
        SELECT AVG(grade) 
        FROM grades 
        INNER JOIN students ON grades.student_id = students.student_id
        WHERE students.group_id = s.group_id
    ) AS avg_group_grade
FROM 
    students s
INNER JOIN 
    grades g ON s.student_id = g.student_id;

Тепер:

  • Замість MAX() ми використовуємо AVG() для обчислення середньої оцінки в групі.
  • Отримуємо "живий" аналіз даних.

Обмеження та рекомендації

Підзапити в SELECT потужні, але їх використання вимагає обережності:

  1. Продуктивність. Кожен підзапит виконується для кожного рядка основного запиту. Це може сповільнити виконання SQL-запиту, якщо таблиці великі. Наприклад, якщо в таблиці 1000 студентів, то підзапит виконається 1000 разів!
  2. Індекси. Для прискорення виконання таких запитів важливо правильно індексувати стовпці, які беруть участь в умовах WHERE підзапиту.
  3. Читабельність. Намагайся уникати зайвої вкладеності. Якщо підзапити стають занадто складними, подумай про перенесення їх у FROM або створення тимчасових таблиць.

Приклади використання

Давай розглянемо ще кілька цікавих кейсів.

Приклад 3: Кількість курсів у кожного студента

Виводимо таблицю, де для кожного студента показується кількість курсів, на які він записаний. Таблиця enrollments пов’язана зі студентами по student_id:

student_id course_id
1 201
1 202
2 201
3 203

SQL-код:

SELECT
    s.name AS student_name,
    (
        SELECT COUNT(*) 
        FROM enrollments
        WHERE enrollments.student_id = s.student_id
    ) AS course_count
FROM 
    students s;

Тут підзапит рахує кількість записів у таблиці enrollments для кожного студента.

Приклад 4: Флаг "відмінник" для кожного студента

Покажемо, чи є студент відмінником. Нехай критерій для відмінника — це наявність усіх своїх оцінок на рівні 5.

SQL-код:

SELECT
    s.name AS student_name,
    (
        SELECT CASE 
            WHEN MIN(g.grade) = 5 THEN 'Відмінник'
            ELSE 'Не відмінник'
        END
        FROM grades g
        WHERE g.student_id = s.student_id
    ) AS status
FROM 
    students s;

Тут використовується вкладений CASE, щоб присвоїти статус "Відмінник" тільки тим студентам, у яких усі оцінки дорівнюють 5.

Оптимізація підзапитів у SELECT

Ми вже згадували, що продуктивність може стати проблемою. Ось кілька порад для її покращення:

  1. Використовуй індекси. Якщо підзапити фільтрують дані, переконайся, що на використовуваних стовпцях є індекси.
  2. Кешуй результати. Іноді доцільно винести підзапити у представлення (VIEW) або тимчасові таблиці.
  3. Менше вкладеності. Не зловживай багаторазовою вкладеністю, якщо можна використати простіший підхід.

Підзапити у SELECT відкривають купу можливостей для обчислень і аналізу даних. Хоч вони можуть бути ресурсоємними, їх правильно оптимізоване використання робить SQL набагато виразнішим і гнучкішим. Тож не соромся експериментувати й знаходити свої способи покращувати запити!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ