Към съдържанието
wannacode

Подзаявки

Накратко: Подзаявката е SELECT вътре в друга заявка, който връща едно число или списък за WHERE и се ползва с IN, EXISTS или NOT EXISTS.

Проблем

Над средното

Управителят иска да види продуктите, които са по-скъпи от средната цена в магазина. Ти вече знаеш две заявки: едната намира средната цена, другата търси продуктите над дадено число.

Може да пуснеш първата, да препишеш числото и да пуснеш втората. Но утре цените ще са други, а преписаното число ще е остаряло.

Идеята

Подзаявка

Първо средната цена:

SQLбаза: магазин

Сега същата заявка, в скоби, на мястото на числото:

SQLбаза: магазин

Заявка в скоби вътре в друга заявка се казва подзаявка (subquery). Базата първо изпълнява нея, получава 7,036 и после проверява всеки продукт с price > 7.036. Излизат 8 продукта.

Тази подзаявка връща едно число, затова стои там, където би стояло число.

По-точно, за любопитните

Ако подзаявката в сравнение върне няколко реда, SQLite тихо взима първия. В категория 8 („Кухня“) има три продукта, а заявката сравнява само с един от тях:

SQLбаза: магазин

Кой ред е „първият“, не е обещано. PostgreSQL и SQL Server в този случай дават грешка, че подзаявката връща повече от един ред. Ако подзаявката може да върне няколко реда, ползвай IN.

Пробвай

По-скъпи от кашкавала

Покажи името и цената на продуктите, които са по-скъпи от кашкавала. Не пиши цената му на ръка, а я вземи с подзаявка.

SQLбаза: магазин

Идеята

IN със списък от заявка

IN вече го знаеш със списък, написан на ръка: city IN ('Варна', 'Бургас'). Списъкът може да идва и от подзаявка.

Кои клиенти са поръчвали през октомври 2026 г.? Номерата им са в orders, а имената в customers:

SQLбаза: магазин

Подзаявката връща номерата на клиентите с поръчки от 1 октомври нататък. Външната заявка показва клиентите, чийто id е в този списък.

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

Пробвай

Кой купува кафе

Доставчикът на кафе пуска нов вкус и иска да пише на хората, които вече са купували „Кафе на зърна“. Покажи имената им. Полето започва от първата стъпка: номера на продукта.

SQLбаза: магазин

Идеята

EXISTS

Понякога не те интересува какво връща подзаявката, а дали връща нещо. Кои клиенти още нямат нито една поръчка?

SQLбаза: магазин

EXISTS (…) е вярно, ако подзаявката върне поне един ред. NOT EXISTS е обратното. Какво пише след SELECT в подзаявката, няма значение, затова е SELECT 1.

Тук подзаявката гледа реда отвън: o.customer_id = c.id, където c е клиентът, който външната заявка проверява в момента. Това е нова идея и в следващия урок ще я разгледаме отблизо.

Виж го

NOT IN и един NULL

Управителят подрежда менюто на сайта и пита кои категории нямат нито един продукт. Очаква „Храни“ и „Дом“: те съдържат само подкатегории. Ето първия опит:

SQLбаза: магазин
1. Защо NOT IN върна празен резултат, а не „Храни“ и „Дом“?

Това е капанът от урока за NULL, но сега NULL идва от подзаявката и не се вижда в заявката. NOT EXISTS не сравнява стойности, а пита дали има такъв продукт, и NULL не му пречи:

SQLбаза: магазин

Когато подзаявката е по колона, която може да е NULL, ползвай NOT EXISTS или добави WHERE category_id IS NOT NULL в подзаявката.

Упражнение

Две задачи

1. Отделът за качество иска да звънне на клиентите, които имат поне една отказана (cancelled) поръчка.

Покажи имената на клиентите с поне една отказана поръчка.

SQLбаза: магазин

2. Маркетингът подготвя кампания „Напиши отзив“ за продуктите, за които още никой не е писал.

Покажи имената на продуктите без нито един отзив (таблицата reviews).

SQLбаза: магазин

Тест

Провери се

1. Какво трябва да върне подзаявката в WHERE price > (…)?
2. Какво проверява EXISTS (подзаявка)?
3. Подзаявката в NOT IN (…) може да върне NULL. Какво е по-сигурно?
4. Защо WHERE price > (SELECT AVG(price) FROM products) е по-добро от WHERE price > 7.036?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·