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

Пекарната, етап 2: данните

Накратко: Вторият етап пълни таблиците на пекарната с INSERT, RETURNING и INSERT … SELECT, а първата поръчка се записва в транзакция.

Проблем

Празни таблици

Таблиците от етап 1 са готови и празни. Пекарната има три категории, осем продукта, пет клиенти и първите си поръчки. В този етап ги записваш, и всяко правило от етап 1 ще пази данните.

Всички полета тръгват от базата, която си направил досега: петте таблици и данните от предишните стъпки на етапа.

Идеята

Първият ред

INSERT INTO таблица (колони) VALUES (стойности) записва ред. Колоната id не е в списъка: INTEGER PRIMARY KEY без стойност получава следващото число сам.

SQLпразна база

Колоните в скобите са важни. INSERT INTO categories VALUES (1, 'Хляб') също работи, но зависи от реда на колоните в таблицата и се чупи при първата нова колона.

Пробвай

Трите категории

Запиши трите категории с един INSERT: Хляб, Сладкиши и Напитки, в този ред (хлябът да е 1, сладкишите 2, напитките 3).

SQLпразна база

Идеята

Какво записа базата

Програмата често трябва да знае номера на новия ред, например за да покаже „Продуктът е добавен с номер 1“. RETURNING връща колоните на записания ред:

SQLпразна база

RETURNING връща и стойностите, които базата е сложила сама: без stock в списъка щеше да върне 0 от DEFAULT. Осемте продукта се записват с един INSERT:

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

RETURNING има в SQLite от версия 3.35 и в PostgreSQL. В MySQL го няма: там номерът се взима с LAST_INSERT_ID(), а в SQLite и със last_insert_rowid().

Виж го

Правилата пазят

Правилата от етап 1 вече работят. Продукт с цена 0:

SQLпразна база

Продукт в категория 9, която я няма:

SQLпразна база

Продукт без име:

SQLпразна база

Нито един от трите не влиза. Грешката идва от базата, затова е все едно кой я праща: сайтът, скрипт за внос от Excel или колега в конзолата.

Пробвай

Клиентите

Запиши петте клиента с един INSERT (колони name, email, city): Иван Колев, ivan.kolev@example.com, София; Ана Петрова, ana.petrova@example.com, Пловдив; Борис Николов, boris.nikolov@example.com, София; Десислава Маринова, desislava.marinova@example.com, Варна; Калин Тодоров, kalin.todorov@example.com, без град.

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

UNIQUE сравнява текста буква по буква: Ivan.Kolev@example.com и ivan.kolev@example.com са два различни имейла за базата. Затова програмата прави имейла с малки букви, преди да го запише, или таблицата пази UNIQUE върху lower(email) с индекс (CREATE UNIQUE INDEX … ON customers (lower(email))).

Виж го

Същият имейл

SQLпразна база

Иван от Пловдив е друг човек със същия имейл, а базата не го пуска. Регистрацията в сайта показва точно тази грешка като „Този имейл вече е регистриран“.

Идеята

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

Поръчка без status получава 'new' от DEFAULT:

SQLпразна база

Истинската поръчка обаче са два вида редове: един в orders и няколко в order_items. Ако програмата падне между тях, остава поръчка без нито един продукт. Затова двете се пишат в транзакция: BEGIN, вмъкванията, COMMIT. До COMMIT нищо не е окончателно.

Пробвай

Първата поръчка

Иван (клиент 1) поръча на 2026-10-01 два селски хляба (продукт 1 по 2.40) и три кроасана (продукт 4 по 1.30). Поръчката е доставена. Запиши я в една транзакция: поръчката (тя ще е номер 1) и двата ѝ реда.

SQLпразна база

Виж го

Отказ

Програмата е записала поръчката и разбира, че нещо не е наред (картата е отхвърлена, редът е спрял с грешка). Тогава вместо COMMIT праща ROLLBACK:

SQLпразна база

По време на транзакцията поръчките са 2, а след ROLLBACK пак 1: втората е изчезнала, все едно не е имало INSERT.

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

Тук всяко поле спира на първата грешка, като конзолата. Програмата прави същото с try: при изключение праща ROLLBACK. Транзакцията не се отменя сама при грешка в една заявка, затова ROLLBACK е работа на програмата.

Виж го

Останалите поръчки

Поръчките от 2 до 6 се записват по същия начин. Ето ги, с броя поръчки по статус накрая:

SQLпразна база

Поръчка 4 е отказана, 5 е платена и чака доставка, а 6 е нова. Калин (клиент 5) още не е поръчвал.

Упражнение

Цената от продукта

Сайтът не знае цените наизуст. Когато клиентът купи, цената се взима от products в този момент и се записва в реда. INSERT … SELECT записва редовете, които връща един SELECT.

Калин (клиент 5) поръчва днес две багети (продукт 3). Запиши поръчката (тя ще е номер 7, датата е date('now')) и реда ѝ, като unit_price се взима от products с INSERT … SELECT.

SQLпразна база

Идеята

Пълната база

Шестте поръчки са в базата. Колко реда има всяка таблица:

SQLпразна база

Следващият етап задава въпроси към тези данни: менюто, сметката на всяка поръчка, кой какво купува.

Тест

Провери се

1. В INSERT INTO categories (name) VALUES (…) няма id. Откъде идва?
2. Поръчката влезе, а редът ѝ спря с грешка. Какво прави програмата?
3. Защо при новия ред на поръчката цената се взима с SELECT … FROM products, а не се пише 1.60 на ръка?

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