Ограничение CHECK в SQLite: синтаксис и примеры

CHECK в SQLite позволяет валидировать данные прямо на уровне таблицы. Это удобный способ отсеивать некорректные значения ещё до того, как они попадут в базу. Ограничение работает при INSERT и UPDATE, поэтому хорошо подходит для бизнес-правил, которые должны соблюдаться независимо от прикладного кода

Вся рубрика SQLite: уроки, инструменты и примеры

Как работает CHECK в SQLite

SQLite вычисляет выражение внутри CHECK каждый раз при изменении строки. Если выражение возвращает 0, операция прерывается с ошибкой ограничения. Если результат ненулевой или NULL, строка считается допустимой

Это важно на практике: CHECK не заменяет типизацию, но помогает жёстче контролировать данные в тех местах, где одного NOT NULL или UNIQUE недостаточно

По этой теме полезно отдельно посмотреть EXPLAIN QUERY PLAN: план выполнения SQL-запроса в SQLite, чтобы расширить контекст и сравнить подходы

По этой теме полезно отдельно посмотреть Создание Flutter-приложения с SQLite, BLoC и Streams, чтобы расширить контекст и сравнить подходы

Синтаксис ограничения CHECK

Ограничение можно задать на уровне столбца:

CREATE TABLE products (
  id INTEGER PRIMARY KEY,
  price REAL CHECK (price >= 0)
);

Или на уровне всей таблицы:

CREATE TABLE employees (
  id INTEGER PRIMARY KEY,
  salary REAL,
  bonus REAL,
  CHECK (salary >= 0 AND bonus >= 0)
);

Первый вариант удобен для простых проверок одного поля, второй — для правил, которые зависят сразу от нескольких столбцов

Пример проверки на уровне столбца

Допустим, в таблице контактов возраст не должен быть меньше 18:

CREATE TABLE contacts (
  contact_id INTEGER PRIMARY KEY,
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL,
  age INTEGER NOT NULL CHECK (age >= 18)
);

Корректная вставка пройдёт:

INSERT INTO contacts(first_name, last_name, age)
VALUES ('Ivan', 'Petrov', 29);

А некорректная завершится ошибкой:

INSERT INTO contacts(first_name, last_name, age)
VALUES ('Anna', 'Smirnova', 16);

Такой подход полезен, когда правило должно выполняться всегда, даже если в приложение добавятся новые точки записи данных

Пример проверки на уровне таблицы

Теперь пример, где условие связано с несколькими полями:

CREATE TABLE products (
  product_id INTEGER PRIMARY KEY,
  list_price REAL NOT NULL,
  discount REAL NOT NULL DEFAULT 0,
  CHECK (list_price >= discount AND discount >= 0)
);

Здесь ограничение гарантирует сразу две вещи:

  • скидка не может быть отрицательной
  • скидка не может быть больше базовой цены

Это уже типичный production-кейс, потому что подобные ошибки часто проскакивают в импортерах, административных формах и интеграциях

Что важно знать про ограничения CHECK

Есть несколько особенностей:

  • выражение не может содержать подзапрос
  • CHECK не исправляет данные, а только блокирует неверную запись
  • сложные бизнес-правила лучше держать простыми и проверяемыми

Если правило становится слишком громоздким, его стоит либо упростить, либо вынести в приложение и оставить в SQLite только базовые инварианты

Как добавить CHECK в существующую таблицу

В SQLite нельзя просто выполнить ALTER TABLE ... ADD CHECK ... в привычном виде. Обычно применяется стандартная схема миграции:

  1. создать новую таблицу с нужным CHECK
  2. перенести данные
  3. удалить старую таблицу
  4. переименовать новую

Пример:

CREATE TABLE products_new (
  product_id INTEGER PRIMARY KEY,
  list_price REAL NOT NULL,
  discount REAL NOT NULL DEFAULT 0,
  CHECK (list_price >= discount AND discount >= 0)
);
INSERT INTO products_new(product_id, list_price, discount)
SELECT product_id, list_price, discount
FROM products;
DROP TABLE products;
ALTER TABLE products_new RENAME TO products;

Перед такой миграцией полезно сначала проверить данные, иначе перенос остановится на первой строке, нарушающей новое правило

Когда использовать CHECK в реальном проекте

Ограничение особенно полезно для таких правил:

  • возраст не меньше минимального порога
  • цена и скидка не противоречат друг другу
  • дата окончания не раньше даты начала
  • количество не уходит в отрицательные значения

Если такие условия важны для целостности данных, лучше продублировать их в самой базе, а не надеяться только на код приложения

Частые ошибки

Первая ошибка — пытаться использовать CHECK для очень сложной предметной логики. Чем проще и прозрачнее выражение, тем легче сопровождать схему

Вторая ошибка — считать, что NULL всегда ведёт к ошибке. В SQLite выражение CHECK, вернувшее NULL, не считается нарушением, и это нужно учитывать при проектировании

Третья ошибка — добавлять ограничение в существующую таблицу без предварительной проверки старых данных

CHECK в SQLite — это простой и полезный инструмент для валидации данных на уровне схемы. Его стоит использовать там, где правило должно соблюдаться всегда и не зависеть от конкретного клиента, формы или скрипта импорта

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x