Пекарната, етап 6: отчетът, копието и DROP
Накратко: Последният етап прави отчет с прозоречни функции, копие на базата с VACUUM INTO и маха всичко с DROP в правилния ред.
Проблем
Месецът свърши
Октомври приключи. Пекарната иска отчет: как растат приходите ден по ден, кой е най-добрият клиент и какъв дял от парите идва от него. После иска копие на базата, преди да започне нов сезон. А ти, за да видиш целия път, ще махнеш базата парче по парче, докато не стане празна, както в началото на етап 1.
Полетата тръгват от базата след етап 5: данните, индексът, изгледът order_totals, тригерът take_stock и колоната phone.
Идеята
Натрупаната сума
Прозоречна функция смята стойност от няколко реда, без да ги слива в един. SUM(t.total) OVER (ORDER BY o.ordered_at) е сумата на всички поръчки до този ред включително:
Така се вижда как месецът расте до 47 €, без отказаната поръчка.
Пробвай
Отчетът
Отчет по клиенти, без отказаните поръчки: името, похарченото (spent), делът от всички приходи в проценти (share, закръглен до 1 знак) и мястото в класирането (place, с RANK). Подреди по място. Сумите вземи от изгледа order_totals.
Решение
SELECT c.name,
SUM(t.total) AS spent,
ROUND(100.0 * SUM(t.total) / SUM(SUM(t.total)) OVER (), 1) AS share,
RANK() OVER (ORDER BY SUM(t.total) DESC) AS place
FROM order_totals t
JOIN customers c ON c.id = t.customer_id
WHERE t.status <> 'cancelled'
GROUP BY c.id
ORDER BY place;ROUND(100.0 * SUM(t.total) / SUM(SUM(t.total)) OVER (), 1) и RANK() OVER (ORDER BY SUM(t.total) DESC). Вътрешният SUM е сумата на клиента, а външният с OVER () е сборът на всички клиенти. С / SUM(t.total) всеки има дял 100. Без условието за статуса влиза и Борис с отказаната си поръчка.
По-точно, за любопитните
RANK дава еднакво място на равните и прескача следващото (1, 1, 3). DENSE_RANK не прескача (1, 1, 2), а ROW_NUMBER дава различни номера дори на равните.
Идеята
Копието
Преди голяма промяна (нов сезон, миграция, внос на данни) се прави копие. VACUUM INTO записва цялата база в нов файл, докато тя работи, а ATTACH отваря копието като втора база до първата:
Шестте поръчки и петте таблици са и в копието.
Пусни полето втори път и VACUUM INTO спира: файлът вече го има. Така е и в истинската работа: всяко копие е нов файл с датата в името.
По-точно, за любопитните
В PostgreSQL копието се прави отвън: pg_dump bakery > bakery-2026-10-31.sql и връщане с psql. Копие, което никой не е пробвал да върне, не е копие.
Виж го
Какво зависи от какво
Изгледът order_totals чете от order_items. Ако таблицата изчезне първа:
Изгледът остава, но вече сочи към нищо. Индексите и тригерите на таблица изчезват с нея, изгледите не. Затова първо се махат изгледите. PostgreSQL е по-строг: там DROP TABLE спира, докато има изглед, който чете от таблицата.
Пробвай
Изгледът, тригерът и индексът
Махни изгледа order_totals, тригера take_stock и индекса orders_customer.
Решение
DROP VIEW order_totals;
DROP TRIGGER take_stock;
DROP INDEX orders_customer;DROP VIEW order_totals;, DROP TRIGGER take_stock; и DROP INDEX orders_customer;. Всеки вид обект има свой DROP. Проверката брои изгледите, тригерите и индексите, които са останали (без вътрешните sqlite_autoindex_… на UNIQUE и на двойния ключ).
Виж го
Родителят първи
Таблица, към която други сочат, не може да изчезне, докато има редове, които сочат към нея:
DROP TABLE първо трие всички редове, а външният ключ в orders не дава да изчезнат клиенти с поръчки.
Упражнение
Празна база
Махни петте таблици така, че нито един DROP да не спре с грешка. Накрая в базата не бива да остане нищо.
Решение
DROP TABLE order_items;
DROP TABLE orders;
DROP TABLE products;
DROP TABLE customers;
DROP TABLE categories;От децата към родителите, обратно на етап 1: order_items, orders, products, customers, categories. С categories първа DROP спира, защото продуктите сочат към категориите. Без последния DROP остава една таблица.
По-точно, за любопитните
orders преди order_items също минава, но по случайност: ON DELETE CASCADE изтрива редовете на поръчките, преди таблицата да изчезне. Без CASCADE същият ред спира. Сигурният ред е винаги от децата към родителите. В PostgreSQL DROP TABLE … CASCADE маха и всичко, което зависи от таблицата: удобно и опасно.
Идеята
Целият път
Базата е празна, както в началото. По пътя:
- Етап 1: петте
CREATE TABLEс ключове,NOT NULL,UNIQUE,CHECK,DEFAULTиCASCADE. - Етап 2:
INSERT,RETURNING, транзакция сBEGINиCOMMIT,ROLLBACKиINSERT … SELECT. - Етап 3: въпросите с
JOIN,LEFT JOIN,GROUP BY,WITHиCOALESCE. - Етап 4:
UPDATE,DELETEи upsert, с правилата, които спират грешното. - Етап 5: индекс, изглед, тригер и
ALTER TABLE. - Етап 6: отчет с прозорци, копие с
VACUUM INTOиDROP.
На твоя компютър последната стъпка е изтриването на файла bakery.db. В PostgreSQL е DROP DATABASE bakery;, пуснато от друга база, докато никой не е свързан към нея.
Тест
Провери се
Свързани уроци
Раздел „Свързани уроци“- Нужно отпреди: Външни ключове: връзки между таблиците · Изгледи · Тригери · Индекси
- Задачи по темата: Проект: пекарната от нула