DML: INSERT, UPDATE, DELETE і простий SELECT
Структуру таблиць створюють командами DDL, але порожня схема ще не розв'язує прикладних задач. Інформаційна система повинна додавати нові факти, змінювати актуальний стан, вилучати непотрібні записи та читати дані. Для цього використовують команди маніпулювання даними.
У цій лекції всі приклади виконуються в PostgreSQL на одній таблиці інтернет-магазину. Їх можна послідовно запускати в pgAdmin або DBeaver.
Цілі лекції
Після опрацювання матеріалу ви зможете:
- додавати один або кілька рядків командою
INSERT INTO; - отримувати результат зміни за допомогою PostgreSQL
RETURNING; - безпечно застосовувати
UPDATEіDELETEз умовою; - пояснювати призначення основних частин простого
SELECT; - вибирати окремі стовпці, задавати псевдоніми та обчислювати вирази;
- сортувати результат за одним або кількома критеріями через
ORDER BY.
Передумови
Потрібні базові знання про таблиці, рядки, стовпці, первинний ключ, типи даних і команду CREATE TABLE. Також потрібне підключення до PostgreSQL із редактором SQL.
1. Навчальний стенд
Щоб усі приклади давали узгоджений результат, створимо одну таблицю products. Команди DROP TABLE і CREATE TABLE тут лише готують стенд; їхню роль як DDL розглянуто в попередніх лекціях.
DROP TABLE IF EXISTS products;
CREATE TABLE products (
product_id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name varchar(100) NOT NULL,
category varchar(50) NOT NULL,
price numeric(10, 2) NOT NULL CHECK (price >= 0),
stock integer NOT NULL DEFAULT 0 CHECK (stock >= 0),
is_active boolean NOT NULL DEFAULT true
);
PostgreSQL сам генерує product_id. Для stock та is_active визначено типові значення, а перевірки не дозволяють зберігати від'ємну ціну або кількість.
2. DML і життєвий цикл рядка
DML (Data Manipulation Language) - частина SQL для роботи з даними всередині вже створених таблиць. У цій лекції розглядаємо чотири базові дії:
| Дія | Команда | Результат |
|---|---|---|
| Додати | INSERT | У таблиці з'являється новий рядок |
| Прочитати | SELECT | СКБД формує таблицю результату |
| Змінити | UPDATE | Значення в наявних рядках оновлюються |
| Видалити | DELETE | Вибрані рядки вилучаються |
Ці дії часто називають CRUD: Create, Read, Update, Delete. Це зручна відповідність, але SQL-команди мають власні точні назви й правила.
3. Додавання одного рядка: INSERT INTO
Загальна форма додавання одного рядка:
INSERT INTO table_name (column_1, column_2)
VALUES (value_1, value_2);
Додамо перший товар:
INSERT INTO products (name, category, price, stock)
VALUES ('Підставка для ноутбука', 'Аксесуари', 899.00, 12);
Порядок значень у VALUES відповідає порядку стовпців після назви таблиці. Рядкові значення записують в одинарних лапках, а десяткові числа в SQL - із крапкою.
Стовпці product_id та is_active не вказано навмисно. Ідентифікатор згенерує PostgreSQL, а is_active отримає типове значення true.
Рекомендовано явно перелічувати стовпці навіть тоді, коли значення задаються майже для всього рядка. Такий запит легше читати, і він менше залежить від порядку стовпців у таблиці.
4. Додавання кількох рядків
Одна команда може додати одразу кілька товарів. Набори значень відокремлюють комами:
INSERT INTO products (name, category, price, stock)
VALUES
('Бездротова миша', 'Периферія', 749.00, 25),
('Механічна клавіатура', 'Периферія', 1599.00, 10),
('Кабель USB-C', 'Аксесуари', 299.00, 40),
('Вебкамера', 'Периферія', 2199.00, 7);
Кожні дужки описують один новий рядок. Кількість і порядок значень у всіх наборах мають відповідати переліку стовпців.
Багаторядковий INSERT коротший за серію однакових команд і чітко показує, що дані додаються однією операцією. Проте кожен рядок усе одно перевіряється за типами та обмеженнями таблиці.
5. PostgreSQL RETURNING
Після зміни часто потрібно дізнатися, який ідентифікатор отримав новий рядок або які значення фактично збережено. У PostgreSQL для цього є RETURNING:
INSERT INTO products (name, category, price, stock)
VALUES ('USB-мікрофон', 'Аудіо', 2799.00, 5)
RETURNING product_id, name, price, stock;
Очікуваний результат після чистого запуску стенда й попередніх вставок:
| product_id | name | price | stock |
|---|---|---|---|
| 6 | USB-мікрофон | 2799.00 | 5 |
RETURNING не є окремим читанням усієї таблиці. Воно повертає стовпці саме тих рядків, яких торкнулася команда. Запис RETURNING * повертає всі їхні стовпці:
INSERT INTO products (name, category, price)
VALUES ('Килимок для миші', 'Аксесуари', 399.00)
RETURNING *;
Тут stock матиме типове значення 0, а is_active - true.
RETURNING можна використовувати також після UPDATE і DELETE. Це розширення PostgreSQL особливо зручне для застосунків і для перевірки навчальних запитів.
6. Безпечне оновлення: UPDATE
Команда UPDATE змінює значення в наявних рядках:
UPDATE table_name
SET column_1 = new_value,
column_2 = new_value
WHERE condition;
Оновимо ціну й залишок кабелю з ідентифікатором 4:
UPDATE products
SET price = 329.00,
stock = 35
WHERE product_id = 4
RETURNING product_id, name, price, stock;
Очікуємо один рядок із новими значеннями. Умова WHERE product_id = 4 визначає, який саме рядок потрібно змінити.
Чому WHERE критично важливий
Синтаксично WHERE для UPDATE не є обов'язковим. Але команда без умови змінює кожен рядок таблиці:
-- Небезпечно: деактивує всі товари.
UPDATE products
SET is_active = false;
PostgreSQL не здогадається, який рядок мав на увазі автор. Відсутність WHERE не є синтаксичною помилкою.
Безпечна звичка перед зміною:
- сформулювати умову;
- перевірити нею рядок через
SELECT; - перенести ту саму умову в
UPDATE; - додати
RETURNINGі перевірити фактичний результат.
SELECT product_id, name, price, stock
FROM products
WHERE product_id = 4;
UPDATE products
SET price = 329.00,
stock = 35
WHERE product_id = 4
RETURNING product_id, name, price, stock;
У цій лекції використано лише просту перевірку рівності за первинним ключем. Складні оператори фільтрації та поєднання умов розглянемо в лекції 13.
7. Безпечне видалення: DELETE
DELETE видаляє рядки, але не стовпці й не саму таблицю:
DELETE FROM table_name
WHERE condition;
Спочатку переглянемо товар, потім видалимо його та попросимо PostgreSQL показати вилучений рядок:
SELECT product_id, name
FROM products
WHERE product_id = 5;
DELETE FROM products
WHERE product_id = 5
RETURNING product_id, name;
Результат RETURNING підтвердить видалення вебкамери. Після цього звичайний SELECT із тією самою умовою не поверне рядків.
Як і UPDATE, команда DELETE без WHERE діє на всю таблицю:
-- Небезпечно: видаляє всі рядки products.
DELETE FROM products;
Таблиця після цього продовжить існувати, але буде порожньою. Перед DELETE завжди перевіряйте умову окремим SELECT. У реальних системах додатковий захист дають транзакції, резервні копії, права доступу та правила предметної області; ці механізми розглядатимуться пізніше.
8. Простий SELECT
SELECT читає дані та формує результат запиту. Результат виглядає як таблиця, але не обов'язково зберігається в базі як нова таблиця.
Базова структура запиту цієї лекції:
SELECT expressions
FROM table_name
WHERE condition
ORDER BY sort_expression;
Не всі частини обов'язкові. Для перегляду всіх стовпців використовують *:
SELECT *
FROM products;
Для прикладного запиту краще явно вибирати потрібні стовпці:
SELECT product_id, name, price
FROM products;
Явний перелік робить результат передбачуваним, не передає зайвих даних і показує призначення запиту.
Запис запиту і концептуальний порядок
SQL записують, починаючи із SELECT, але для розуміння простого запиту корисно уявляти інший концептуальний порядок:
FROM- визначити джерело рядків;WHERE- залишити рядки, що відповідають умові;SELECT- сформувати потрібні стовпці та вирази;ORDER BY- упорядкувати готовий результат.
Це навчальна модель, а не буквальний опис внутрішнього алгоритму PostgreSQL. Оптимізатор може фізично виконувати операції інакше, зберігаючи той самий правильний результат.
9. Псевдоніми й обчислювані вирази
Псевдонім AS задає зрозумілу назву стовпця в результаті, не перейменовуючи стовпець у таблиці:
SELECT
name AS product_name,
price AS unit_price
FROM products;
У списку SELECT можна виконувати обчислення. Вартість усього запасу товару дорівнює ціні одиниці, помноженій на кількість:
SELECT
name AS product_name,
price,
stock,
price * stock AS inventory_value
FROM products;
Вираз обчислюється для кожного рядка. inventory_value існує в результаті цього запиту; команда не додає однойменного стовпця до products і не зберігає обчислені числа.
Ще один приклад - навчальний розрахунок ціни з коефіцієнтом 1.20:
SELECT
name,
price AS price_without_tax,
price * 1.20 AS price_with_tax
FROM products;
Це лише демонстрація виразу. Реальні правила податків і округлення потрібно задавати відповідно до вимог предметної області.
10. Основи ORDER BY
Без ORDER BY порядок рядків результату не гарантований. Те, що сьогодні рядки відобразилися за ідентифікатором, не створює правила на майбутнє.
Сортування за зростанням задають ASC; це типовий напрям:
SELECT name, price
FROM products
ORDER BY price ASC;
Сортування за спаданням задають DESC:
SELECT name, price
FROM products
ORDER BY price DESC;
Можна визначити кілька критеріїв. Наступний критерій застосовується до рядків, у яких попередній має однакове значення:
SELECT category, name, price
FROM products
ORDER BY category ASC, price DESC;
Сортувати можна й за псевдонімом обчисленого стовпця:
SELECT
name,
price * stock AS inventory_value
FROM products
ORDER BY inventory_value DESC;
ORDER BY змінює порядок рядків лише в результаті запиту. Фізично «пересортувати таблицю» цією командою не можна.
Практичні завдання
Перед виконанням завдань повторно запустіть код із розділу «Навчальний стенд», а потім багаторядковий INSERT із п'ятьма товарами: спочатку підставку для ноутбука, далі мишу, клавіатуру, кабель і вебкамеру. Так ідентифікатори знову будуть від 1 до 5.
Завдання 1. Додайте товар і перевірте результат
Додайте товар Навушники категорії Аудіо із ціною 1899.00, залишком 8 і типовим активним станом. Не задавайте product_id та is_active вручну. За допомогою RETURNING виведіть усі стовпці створеного рядка.
Перевірте, що товар отримав ідентифікатор 6, а is_active дорівнює true.
Завдання 2. Безпечно змініть і видаліть рядок
Продовжуйте працювати зі станом після завдання 1.
- Через
SELECTперевірте товар ізproduct_id = 6. - Змініть його ціну на
1799.00, а залишок - на11. - Використайте ту саму умову та
RETURNING product_id, name, price, stock. - Ще раз перевірте рядок через
SELECT. - Видаліть лише цей товар і поверніть його
product_idтаname. - Переконайтеся, що повторний
SELECTза ідентифікатором6не повертає рядків.
Завдання 3. Сформуйте звіт про запас
Для товарів, що залишилися після завдання 2, сформуйте результат із такими стовпцями:
- назва товару з псевдонімом
product_name; - ціна з псевдонімом
unit_price; - кількість
stock; - обчислена вартість запасу
price * stockіз псевдонімомinventory_value.
Відсортуйте результат за inventory_value від найбільшого значення до найменшого. Таблицю products змінювати не потрібно.
Підсумок
INSERT INTOдодає рядки; явний перелік стовпців робить команду зрозумілішою та надійнішою.- Один
INSERTможе містити кілька наборів уVALUES. - PostgreSQL
RETURNINGпоказує дані рядків, яких торкнулисяINSERT,UPDATEабоDELETE. UPDATEзмінює, аDELETEвидаляє всі рядки, що відповідають умові; безWHEREвони діють на всю таблицю.- Перед зміною або видаленням умову варто перевіряти через
SELECT, а результат - черезRETURNING. SELECTформує результат із вибраних стовпців і виразів; псевдонім не змінює схему таблиці.- Спрощений концептуальний порядок простого запиту:
FROM→WHERE→SELECT→ORDER BY. - Лише
ORDER BYгарантує потрібне впорядкування результату. - Розширені оператори фільтрації, поєднання умов,
LIMITтаOFFSETналежать до лекції 13. Агрегації таJOINрозглядатимуться пізніше.
