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

Отчет на стъпки: WITH

Накратко: WITH (CTE) дава име на всяка стъпка от заявката, така че тя се чете отгоре надолу, а една стъпка може да се ползва повече от веднъж.

Проблем

Отчет отвътре навън

Собственичката иска списък на клиентите, които са похарчили над 100 € (без отказаните поръчки), с броя на поръчките им. С подзаявки във FROM вече можеш да го направиш:

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

Резултатът е верен. Но опитай да кажеш какво прави заявката: трябва да започнеш от най-вътрешните скоби и да вървиш навън. След месец и ти няма да я познаеш.

Идеята

WITH

WITH дава име на една стъпка, преди основната заявка:

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

order_totals е стойността на всяка поръчка, която не е отказана: 53 реда. След WITH името се ползва като таблица. Такава именувана стъпка се казва CTE (common table expression).

Стъпките може да са няколко, разделени със запетаи. Всяка вижда стъпките преди себе си:

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

Същият отчет като в началото, но се чете отгоре надолу: стойност на всяка поръчка, после сума за всеки клиент, после само тези над 100 €. Излизат седем клиенти, начело с Мария (375,70 € в 12 поръчки).

Пробвай

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

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

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

Виж го

Колко живее името

Името от WITH важи само за заявката, на която е част. Тук има две заявки: първата брои поръчките, втората пита пак за order_totals:

SQLбаза: магазин
1. Защо втората заявка не намира order_totals?

WITH не създава таблица в базата. Ако една стъпка ти трябва в много отчети, за това има изгледи (VIEW), които ще срещнем в модула за схемата.

Идеята

Кога WITH, кога подзаявка

Резултатът е един и същ. Разликата е за човека, който чете:

  • кратко условие като price > (SELECT AVG(price) FROM products) е най-ясно на място, като подзаявка;
  • отчет от няколко стъпки е по-ясен с WITH: всяка стъпка има име, което казва какво е;
  • стъпка, която трябва два пъти, се пише веднъж.

Удобно е и при търсене на грешка: смени последния SELECT с SELECT * FROM order_totals и виждаш какво дава всяка стъпка.

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

Дали базата изпълнява всяка стъпка отделно или ги слива в една заявка, решава тя. В PostgreSQL преди версия 12 всяко WITH се изпълняваше отделно, а от версия 12 базата може да го слее с основната заявка. Ако някога WITH-заявка е по-бавна от същата с подзаявки, причината често е там.

Упражнение

Три задачи

1. Отделът по продажби иска оборота по градове, за да реши къде да пусне реклама.

Покажи града и оборота от поръчките на клиентите от него (без отказаните), закръглен до два знака. Започни от стъпката order_totals.

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

2. Кои категории са донесли над 200 € (без отказаните поръчки)?

Покажи името на категорията и оборота ѝ (сумата на количество по единична цена), само за категориите с оборот над 200 €. Направи една стъпка с оборота по category_id и после я свържи с categories.

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

3. В модула за свързване направи с CROSS JOIN мрежата от всеки град и всяка подкатегория. Сега я попълни: оборотът за всяка двойка, с 0 там, където продажби няма.

Покажи града, името на подкатегорията (колона category) и оборота (колона revenue) от клиентите на този град в тази подкатегория (без отказаните поръчки), закръглен до два знака. За двойките без продажби оборотът е 0. Полето вече има мрежата.

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

Тест

Провери се

1. Как се пишат две стъпки в едно WITH?
2. Какво прави WITH order_totals AS (…) с базата?
3. Какво дава WITH, което подзаявката във FROM не дава?

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