Когда база данных говорит «нет»
Несколько раз в этом уроке база данных отклоняла изменение. Такие ошибки приходят от ограничений (constraints): правил, которые таблица устанавливает для своих данных. База данных проверяет их при каждом INSERT и UPDATE (а внешние ключи — и при каждом DELETE), и если инструкция нарушила бы одно из них, она отклоняет всю инструкцию и ничего не меняет. Правила — часть базы данных, поэтому они защищают данные, кто бы их ни записывал: сайт магазина, складское приложение или вы.
Вот ограничения Pixel Shop, каждое с примером сообщения:
- NOT NULL: у столбца должно быть значение. В Pixel Shop пустыми могут быть только дата выхода игры, город и рекомендовавший клиент у клиента и комментарий отзыва. Игра без возрастного ограничения получит
NOT NULL constraint failed: games.age_rating. - UNIQUE: никакие две строки не могут иметь одинаковое значение в этом столбце. У каждого клиента свой адрес электронной почты, поэтому второй клиент с
emma.clark@mail.comполучитUNIQUE constraint failed: customers.email. Первичный ключ тоже уникален: занятый ID получитUNIQUE constraint failed: games.id, а поскольку первичный ключ отзыва — это игра и клиент вместе, каждый клиент может оставить отзыв на каждую игру только один раз. - CHECK: условие, которому должна удовлетворять каждая строка. В Pixel Shop это оценка от 1 до 5, количество больше 0 и статус
paidилиrefunded. В сообщении показано условие:CHECK constraint failed: stars BETWEEN 1 AND 5. - FOREIGN KEY: внешний ключ должен указывать на существующую строку. Отзыв от клиента 99 получит
FOREIGN KEY constraint failed, как и удаление строки, на которую указывают другие строки. В этом сообщении не сказано, о каком столбце речь. - Типы: в таблицах STRICT столбец
INTEGERхранит только целые числа, а столбецTEXT— только текст. Текст в числовом столбце получитcannot store TEXT value in INTEGER column reviews.stars. Целое число в кавычках, например'5', без проблем превращается в число 5, но'five'или4.5отклоняются.
Если сразу добавляется несколько строк и одна из них нарушает правило, не попадёт ни одна:
INSERT INTO reviews (game_id, customer_id, stars)
VALUES
(4, 4, 5),
(14, 2, 6);Error on line 1: CHECK constraint failed: stars BETWEEN 1 AND 5Первый отзыв в порядке, но у второго оценка 6, поэтому база данных отклоняет всю инструкцию, и первый отзыв тоже не добавляется.
Если инструкция нарушает сразу несколько правил, база данных сообщает об одном из них. Исправьте его и запустите инструкцию снова — возможно, вы получите следующее. Таблица и столбец в сообщении подскажут, где искать. А откуда берутся правила? Они записаны в определении каждой таблицы — в инструкции CREATE TABLE, которая её создала. В следующем уроке вы напишете собственные таблицы, вместе со всеми ограничениями.
Типичная ошибка: убирать ошибку с дороги вместо того, чтобы исправлять данные. Когда новый клиент получает UNIQUE constraint failed: customers.email, решение — не менять в адресе букву за буквой, пока база не согласится. Возможно, клиент уже есть в таблице, или адрес неверный. Ограничение нашло настоящую проблему, так что выясните, какую.
Задание
- 1
INSERTв редакторе должен добавить нового клиента, Ruby Ward, но база данных его отклоняет. Запустите его, прочитайте ошибку, исправьтеINSERTи запускайте снова, пока он не заработает: в нём две ошибки. Ruby зарегистрировалась 2026-01-12, а адрес вINSERTпринадлежит Emma Clark; собственный адрес Ruby —ruby.ward@mail.com. Запрос ниже тогда покажет её:id name email city joined 15 Ruby Ward ruby.ward@mail.com Leeds 2026-01-12 - 2
Ruby делает свой первый заказ. Его
INSERTв редакторе пока нет, и в нём тоже есть ошибки. Скопируйте его в конец файла, ниже запроса, запустите файл и исправляйтеINSERT, пока база данных его не примет. Заказ принадлежит Ruby, и он оплачен:INSERT INTO orders (customer_id, ordered_at, status) VALUES (51, '2026-01-12', 'new');Затем покажите ID, клиента, дату и статус заказов Ruby:
id customer_id ordered_at status 31 15 2026-01-12 paid - 3
И позиция заказа: один экземпляр Moon Farm (игра 3) за $20. Скопируйте этот
INSERTтоже в конец файла и исправьте его ошибки:INSERT INTO order_items (order_id, game_id, quantity, price) VALUES (31, 3, 0, '$20');Затем покажите все столбцы позиций заказа 31:
order_id game_id quantity price 31 3 1 20