Онлайн час в Google Meet
Лого на 91. НЕГ „Проф. Константин Гълъбов“

12. клас · Избираем модул · Урок 2

Вложени заявки и подзаявки

Подзаявка на трите места — в WHERE (сравнение, IN, EXISTS), в SELECT като изчислена колона и във FROM като производна таблица; корелирани подзаявки и кога JOIN е по-добрият избор.

Защо пак подзаявки

В Модул 3 (урок „Влагане на заявки“) видяхте основната идея: вътрешен SELECT в скоби на мястото на стойност или на таблица. Тогава работехте в Access с прости примери. Сега ще подредите картината докрай: подзаявката може да стои на три места — в WHERE, в SELECT и във FROM — и на всяко от тях се държи различно. Ще видите и корелираната подзаявка, която „гледа“ реда на външната. След три седмици ще карате AI асистент да ви пише заявки; за да откриете грешката му, трябва да четете подзаявки свободно.

Подзаявка (subquery)

SELECT, вложен в друга заявка и затворен в кръгли скоби. Външната заявка използва резултата му като стойност, като списък от стойности или като таблица.

МястоКакво връща подзаявкатаКак се ползва
WHEREедна стойност / една колона / „има ли редове“сравнение (=, >, <), IN, EXISTS
SELECTточно една стойност за всеки външен редизчислена колона в резултата
FROMцяла таблица (много редове и колони)производна таблица с псевдоним, върху която се работи

Подзаявка в WHERE

Скаларна — една стойност

Най-простият случай: подзаявката връща едно число и го сравняваме с колона. Класиката „над средния успех“ не може да се напише без подзаявка, защото WHERE grade > AVG(grade) е грешка — агрегатите не се допускат в WHERE.

SELECT name, grade
FROM students
WHERE grade > (SELECT AVG(grade) FROM students);

Колона — списък със IN

Ако подзаявката връща много редове, сравнението със = е грешка. Ползвате IN („в списъка“) или NOT IN.

-- Ученици, които имат поне една оценка по БЕЛ (предмет 3)
SELECT name
FROM students
WHERE id IN (SELECT student_id FROM marks WHERE subject_id = 3);

EXISTS — „има ли поне един такъв ред“

EXISTS не гледа стойностите, а само дали подзаявката връща нещо. Затова вътре се пише SELECT 1. Почти винаги е корелирана: условието вътре споменава ред от външната заявка.

-- Ученици без нито една оценка
SELECT name
FROM students s
WHERE NOT EXISTS (SELECT 1 FROM marks m WHERE m.student_id = s.id);

Подзаявка в SELECT

Подзаявка в списъка на колоните трябва да върне точно една стойност за всеки ред на външната заявка. Обикновено е корелирана — пресмята нещо за текущия ученик, клас, предмет.

SELECT s.name,
       (SELECT COUNT(*) FROM marks m WHERE m.student_id = s.id) AS broy_ocenki
FROM students s;
  • Задължително давайте име с AS — иначе колоната се казва колкото целия израз.
  • Ако подзаявката не намери редове: COUNT връща 0, а MAX, AVG и обикновен SELECT връщат NULL. Ще го видите във втория пример при учениците без оценки.
  • Ако върне повече от един ред — грешка (в SQLite мълчаливо се взема първият, което е още по-лошо: грешен резултат без грешка).

Подзаявка във FROM — производна таблица

На мястото на таблица може да застане цял SELECT. Резултатът му е производна таблица (derived table) — съществува само по време на заявката. Най-честата употреба: първо групирате, после работите с обобщените стойности като с обикновени колони — съединявате ги, филтрирате ги, сортирате ги.

SELECT c.name AS klas, t.sreden
FROM (
  SELECT class_id, ROUND(AVG(grade), 2) AS sreden
  FROM students
  GROUP BY class_id
) AS t
JOIN classes c ON c.id = t.class_id
WHERE t.sreden > 5;

Корелирана подзаявка

Корелирана подзаявка

Подзаявка, чието условие използва колона от външната заявка (например s2.class_id = s.class_id). Не може да се изпълни сама — пресмята се наново за всеки ред на външната.

-- Ученици с успех над средния ЗА СВОЯ КЛАС
SELECT s.name, s.grade
FROM students s
WHERE s.grade > (SELECT AVG(s2.grade)
                 FROM students s2
                 WHERE s2.class_id = s.class_id);

Сравнете с първия пример: там средният успех е едно число за цялото училище и подзаявката се пресмята веднъж. Тук за всеки ученик се пресмята средният успех на неговия клас — псевдонимите s и s2 са двете „копия“ на таблицата, както при SELF JOIN от Модул 3.

Подзаявка или JOIN

ПодзаявкаJOIN
Кога е естественапроверка „дали има“, сравнение с обобщена стойност, филтър по списъктрябват ви колони от двете таблици в резултата
Дублиране на редовеняма — външната таблица си остава с редовете сипри 1:M редовете се умножават; трябва DISTINCT или GROUP BY
Четимостследва въпроса на български: „ученици, за които има…“по-кратка при много таблици
Скоросткорелираната се изпълнява за всеки редобикновено един проход; оптимизаторът я обича

Какво трябва да запомниш

  • Подзаявка = SELECT в скоби на мястото на стойност, списък или таблица.
  • В WHERE: една стойност → сравнение; колона → IN / NOT IN; „има ли“ → EXISTS / NOT EXISTS.
  • В SELECT: точно една стойност за всеки външен ред, винаги с AS; липса → NULL (COUNT → 0).
  • Във FROM: производна таблица — AS имена на колоните и псевдоним на таблицата (в MySQL задължително).
  • Корелираната подзаявка споменава външния ред и се изпълнява за всеки ред — удобна, но скъпа.
  • JOIN, когато ви трябват колони от двете таблици; подзаявка, когато проверявате или сравнявате.