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

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

Накратко: Корелираната подзаявка ползва колона от външната заявка и затова се смята наново за всеки ред, а подзаявката във FROM прави от резултата нова таблица.

Проблем

Скъпо за кого?

От предишния урок знаеш кои продукти са над средната цена в магазина:

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

Всичко от кухнята е „скъпо“, а нито един хляб не е. Само че хлябът не се сравнява с тиган. Управителят иска да знае кои продукти са скъпи за своята категория: сиренето срещу млечните, кафето срещу напитките.

Идеята

Свързана подзаявка

Подзаявката може да ползва колона от реда, който външната заявка разглежда в момента:

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

p е продуктът отвън, p2 са продуктите в подзаявката. Условието p2.category_id = p.category_id казва „продуктите от неговата категория“. За белия хляб подзаявката смята средната на хляба (1,60 €), за сиренето средната на млечните (4,66 €).

Такава подзаявка се казва свързана (correlated subquery): тя зависи от реда отвън и се пресмята наново за всеки ред. Обикновената подзаявка от предишния урок дава един и същ отговор за всички редове.

Без кратките имена p и p2 не би станало: и двете са таблицата products, а базата трябва да знае коя category_id е отвън и коя отвътре.

Идеята

Във WHERE

Сега въпросът на управителя: кои продукти са над средната за категорията си?

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

Девет продукта, поне по един от всяка категория: пълнозърнестият хляб е над средното за хляба, а прахът за пране е над средното за почистването.

Подаръчната карта я няма, макар че е за 20 €. Категорията ѝ е NULL, p2.category_id = NULL не е вярно за никой ред, средната е NULL и сравнението е неизвестно. Същият NULL от урока за NULL, само по-скрит.

Пробвай

Последната поръчка

За всеки клиент покажи името му и датата на последната му поръчка (колона last_order). Клиентите без поръчки също трябва да са в списъка.

SQLбаза: магазин
По-точно, за любопитните

По замисъл свързаната подзаявка се изпълнява веднъж за всеки ред отвън: 20 клиенти, 20 пъти. Базите често я пренаписват на нещо по-бързо, но при големи таблици си струва да сравниш с JOIN и GROUP BY. Как се гледа какво прави базата, ще видим в модула за скоростта.

Свързаната подзаявка дава и номера на последната поръчка, не само датата ѝ. В модула за обобщаване видя, че SQLite го позволява с MAX и свободна колона, а другите бази не. Ето начинът, който върви навсякъде:

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

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

Виж го

Средната стойност на поръчка

Счетоводството пита колко е средната стойност на една поръчка. Първият опит:

SQLбаза: магазин
1. AVG(quantity * unit_price) върна 12,92 €, а подзаявката във FROM върна 32,73 €. Кое е средната стойност на поръчка?

Трябват две стъпки: първо стойността на всяка поръчка, после средната на тези стойности. Първата стъпка вече я можеш:

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

Идеята

Подзаявка във FROM

Резултатът на всяка заявка е таблица. Затова може да стои във FROM, там където пишеш име на таблица:

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

Вътрешната заявка прави таблица с 60 реда, по един на поръчка. Външната я чете като всяка друга таблица и смята средното: 32,73 €. Това се казва подзаявка във FROM (derived table). Името след AS е как наричаш новата таблица.

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

SQLite не изисква име на подзаявката във FROM, но MySQL и PostgreSQL до версия 16 го искат задължително. Давай ѝ име винаги и заявката ще върви навсякъде.

Пробвай

Колко продукта има в поръчка

Складът планира кутиите и пита: средно колко различни продукта има в една поръчка? Закръгли до два знака след запетаята (колона avg_lines). Полето вече брои продуктите във всяка поръчка.

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

Упражнение

Две задачи

1. Маркетингът иска да си върне клиентите, които не са поръчвали от лятото.

Покажи имената на клиентите, чиято последна поръчка е преди 1 юли 2026 г.

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

2. Колко харчи средно един клиент в магазина?

Сметни средната сума, която клиент е похарчил за поръчките си без отказаните, закръглена до два знака (колона avg_spent). Броят се само клиентите с поне една поръчка.

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

Тест

Провери се

1. С какво свързаната подзаявка се различава от обикновената?
2. Защо подаръчната карта не излиза сред продуктите над средната за категорията си?
3. Какво е подзаявка във FROM?
4. Клиентите без поръчки излизат ли в WHERE (SELECT MAX(o.ordered_at) …) < '2026-07-01'?

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