Перейти к содержимому

Изменение данных

INSERT добавляет строки, UPDATE изменяет существующие, DELETE удаляет их. Каждая операция проверяется на соответствие типам, ограничениям таблицы и действующим правам. Если несколько операторов составляют одну прикладную операцию, используйте явную транзакцию; последовательность отдельных процессов CLI не является одной транзакцией.

Выполняйте блоки ниже по порядку в одной тестовой базе. Они используют собственную таблицу tasks и не зависят от таблицы сотрудников из учебника.

CREATE TABLE tasks (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
done BOOLEAN NOT NULL DEFAULT false,
revision INTEGER NOT NULL DEFAULT 1
);
INSERT INTO tasks (id, title) VALUES (1, 'inspect'), (2, 'publish');

Указывайте список столбцов явно, чтобы оператор не зависел от физического порядка всех столбцов. Пропущенные столбцы получают объявленные значения по умолчанию. Явный NULL не равнозначен пропуску столбца со значением по умолчанию.

INSERT INTO tasks (id, title) VALUES (3, 'archive')
RETURNING id, title, done;

Результат: 3, archive, false. RETURNING создаёт набор результатов; прочитайте его через интерфейс результатов или курсоров клиента. Не предполагайте, что любая запись возвращает только число затронутых строк. Без RETURNING успешная запись возвращает результат команды; начальный многострочный INSERT затрагивает две строки.

SET задаёт новые значения, WHERE выбирает изменяемые строки. Без WHERE оператор UPDATE применяется ко всем строкам таблицы. Перед массовым изменением проверьте предполагаемую выборку.

UPDATE tasks SET done = true, revision = revision + 1
WHERE id = 1 AND revision = 1
RETURNING id, done, revision;

Результат: 1, true, 2. Условие по revision является прикладной оптимистической проверкой: обновление допускается только пока сохранённая ревизия совпадает со значением, ранее прочитанным приложением. Правило ведения ревизий выбирает приложение, а не база данных.

UPDATE tasks SET title = 'stale update'
WHERE id = 1 AND revision = 1;

Затронуто ноль строк: предыдущее обновление изменило ревизию на 2. Ноль строк не является ошибкой SQL. Приложение должно определить, означает ли это устаревшую ревизию, отсутствие строки или просто отсутствие подходящей работы. Пример не устанавливает семантику изоляции двух конкурентных транзакций.

ON CONFLICT задаёт поддерживаемую политику конфликта выбранного ключа. DO NOTHING оставляет существующую строку без изменения:

INSERT INTO tasks (id, title) VALUES (1, 'duplicate')
ON CONFLICT (id) DO NOTHING;

Затронуто ноль строк. DO UPDATE позволяет заменить выбранные значения предложенными для вставки; excluded.title обозначает предложенное название:

INSERT INTO tasks (id, title) VALUES (1, 'renamed')
ON CONFLICT (id) DO UPDATE SET title = excluded.title
RETURNING id, title;

Результат: 1, renamed. Существующие done и revision сохраняются, поскольку SET их не изменяет. Политика конфликта ключа не является универсальным обработчиком недопустимых типов, прав или посторонних ограничений.

DELETE выбирает строки с помощью WHERE. Без WHERE удаляются все строки, но определение таблицы сохраняется. RETURNING сообщает значения удалённой строки.

DELETE FROM tasks WHERE id = 2 RETURNING id, title;
SELECT id, title, done, revision FROM tasks ORDER BY id;

Удалённая строка: 2, publish. Итоговый SELECT возвращает:

id title done revision
1 renamed true 2
3 archive false 1

В SELECT намеренно указан ORDER BY. RETURNING не задаёт стабильный порядок результатов записи, затрагивающей несколько строк.

Для отмены временного изменения выполняйте BEGIN и ROLLBACK в одном сеансе:

BEGIN;
UPDATE tasks SET title = 'temporary' WHERE id = 1;
ROLLBACK;
SELECT title FROM tasks WHERE id = 1;

Название остаётся renamed. Разницу фиксации и отката объясняет глава учебника о транзакциях. Сетевые клиенты могут предоставлять отдельные методы транзакций вместо приёма управляющего SQL через общий метод выполнения запросов.

Обрабатывайте ошибки явно. Потеря соединения или отсутствие ответа не доказывает, что запись не выполнилась; не повторяйте её вслепую. При нарушении ограничения проверяйте состояние транзакции клиента и при необходимости откатывайте явную транзакцию. Набор примеров также проверяет, что отклонённый многострочный INSERT не оставляет первую строку после конфликта следующей строки с существующим PK.