SQL и Qt

INSERT, UPDATE, DELETE: модификация данных

Введение

Помимо чтения данных (статья 394), приложениям нужно их изменять — в статье разберём три основные команды модификации: INSERT (добавление новых строк), UPDATE (изменение существующих), и DELETE (удаление), вместе с их типичными вариациями и осторожностями, без понимания которых легко случайно изменить или удалить значительно больше данных, чем планировалось.

Концепция

INSERT добавляет одну или несколько новых строк в таблицу, явно или неявно (через позиционное соответствие) указывая значения для столбцов. UPDATE изменяет значения указанных столбцов в существующих строках, отбираемых тем же синтаксисом WHERE, что и в SELECT — без WHERE UPDATE изменит абсолютно все строки таблицы, что почти всегда нежелательно и одна из самых частых, разрушительных ошибок начинающих. DELETE удаляет строки целиком, также отбираемые через WHERE с тем же риском при его отсутствии.

Пример кода: INSERT, UPDATE, DELETE

-- INSERT нескольких строк за одну команду — эффективнее множества отдельных INSERT
INSERT INTO customers (id, name, email) VALUES
    (2, 'Мария Сидорова', 'maria@example.com'),
    (3, 'Алексей Кузнецов', 'alexey@example.com');
-- UPDATE с обязательным WHERE — изменение конкретных, отобранных строк
UPDATE customers
SET email = 'ivan.new@example.com'
WHERE id = 1;

-- UPDATE с вычисляемым значением на основе текущего
UPDATE orders
SET total_amount = total_amount * 1.1 -- увеличение на 10%
WHERE order_date < '2026-01-01';
-- DELETE с WHERE — удаление конкретных строк
DELETE FROM orders
WHERE order_date < '2024-01-01'; -- удаление старых заказов

-- ОПАСНО: DELETE без WHERE удаляет ВСЕ строки таблицы
-- DELETE FROM orders;  -- не делайте так без явного, осознанного намерения
-- Безопасная практика: сначала SELECT с тем же условием, чтобы увидеть, что будет затронуто
SELECT * FROM orders WHERE order_date < '2024-01-01'; -- проверка ПЕРЕД реальным DELETE
-- только после проверки результата — выполнение реального DELETE с тем же условием

Пояснения к коду

Множественный INSERT (вставка нескольких строк в одной команде через перечисление через запятую) — не просто синтаксическое удобство, а часто заметно более эффективный способ вставки множества строк по сравнению с отдельной командой INSERT для каждой строки, поскольку СУБД может обработать всю партию данных за одно обращение, минуя повторяющиеся накладные расходы каждой отдельной транзакции. Паттерн «сначала SELECT с тем же условием, потом DELETE/UPDATE» — практическая мера безопасности, особенно ценная при работе непосредственно в командной строке СУБД с реальными, production-данными, позволяющая визуально убедиться, что условие WHERE действительно отбирает именно те строки, которые предполагалось затронуть, прежде чем выполнять необратимое изменение.

Подводные камни

  • Выполнение UPDATE/DELETE без WHERE по ошибке (забытое условие, или вставка лишнего символа, превратившего условие в синтаксически валидное, но не то, что предполагалось) — это, возможно, самая частая и потенциально катастрофическая ошибка работы с SQL напрямую, способная мгновенно изменить или удалить все данные таблицы без возможности простого отмена в production-окружении без транзакции (статья 408) или backup (статья 431); привычка явно проверять условие через предварительный SELECT (как в последнем примере) — практичная защита от такой ошибки.
  • Отсутствие оборачивания серии связанных модификаций в единую транзакцию (статья 408) — если несколько INSERT/UPDATE/DELETE команд логически должны выполниться все вместе или не выполниться вовсе (например, перевод денег между счетами — одновременное уменьшение одного баланса и увеличение другого), выполнение их как независимых, отдельных команд рискует оставить данные в несогласованном, «наполовину выполненном» состоянии при сбое между отдельными командами.
  • Игнорирование того, что UPDATE/DELETE могут затронуть значительно больше строк, чем ожидалось, из-за неверно сформулированного условия WHERE (например, использование OR там, где логически нужен AND, что расширяет, а не сужает условие отбора) — перед выполнением модификации с нетривиальным условием стоит явно проверить логику условия отдельно через SELECT COUNT(*) с тем же WHERE, сравнив полученное число с ожидаемым количеством затрагиваемых строк.
  • Вставка данных без учёта ограничений ссылочной целостности (внешних ключей, статья 397) — попытка вставить заказ со значением customer_id, не соответствующим никакому реально существующему клиенту, будет отклонена СУБД при правильно настроенном ограничении внешнего ключа, и понимание этого ограничения как защитного механизма (а не просто «ошибки», которую нужно подавить) важно для правильного проектирования порядка операций вставки связанных данных (сначала родительские записи, затем дочерние, ссылающиеся на них).