Помимо приятного триггерного решения @Rolando, в MySQL есть еще один обходной путь этой проблемы (пока не CHECK
будут реализованы ограничения).
Как подражать некоторым CHECK
ограничения в MySQL
Итак, если вы предпочитаете ограничения ссылочной целостности и хотите избежать триггеров (из-за проблем в MySQL, когда у вас есть обе таблицы), вы можете использовать другую небольшую справочную таблицу:
CREATE TABLE age_allowed
( age TINYINT UNSIGNED NOT NULL
, PRIMARY KEY (age)
) ENGINE = InnoDB ;
Заполните его 20 строками:
INSERT INTO age_allowed
(age)
VALUES
(0), (1), (2), (3), ..., (19) ;
Тогда ваш стол будет:
CREATE TABLE test
( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT
, age TINYINT UNSIGNED NOT NULL
, PRIMARY KEY (id)
, CONSTRAINT age_allowed__in__test
FOREIGN KEY (age)
REFERENCES age_allowed (age)
) ENGINE = InnoDB ;
Вам придется удалить доступ на запись к age_allowed
таблице, чтобы избежать случайного добавления или удаления строк.
Этот трюк FLOAT
, к сожалению, не будет работать со столбцами типов данных (слишком много значений между 0.0
и 20.0
).
Как подражать произвольному CHECK
ограничения в MySQL (5.7) и MariaDB (от 5.2 до 10.1)
Поскольку MariaDB добавил вычисляемые столбцы в их версии 5.2 ( версия GA: 2010-11-10 ) и MySQL в версии 5.7 (версия GA: 2015-10-21 ) - как они их называют VIRTUAL
и GENERATED
соответственно - их можно сохранить, то есть сохранить в таблица - они их называют PERSISTENT
и STORED
соответственно - мы можем использовать их, чтобы упростить вышеуказанное решение и, что еще лучше, расширить его, чтобы эмулировать / применять произвольные CHECK
ограничения ):
Как и выше, нам понадобится справочная таблица, но на этот раз с одной строкой, которая будет выступать в роли «якорной» таблицы. Более того, эту таблицу можно использовать для любого количестваCHECK
ограничений.
Затем мы добавляем вычисляемый столбец, который оценивает либо TRUE
/ FALSE
/ UNKNOWN
, точно так же, как CHECK
ограничение - но этот столбец имеет FOREIGN KEY
ограничение для нашей таблицы привязки. Если условие / столбец оценивается FALSE
для некоторых строк, строки отклоняются из-за FK.
Если условие / столбец оценивается как TRUE
или UNKNOWN
( NULL
), строки не отклоняются, в точности так, как это должно происходить с CHECK
ограничениями:
CREATE TABLE truth
( t BIT NOT NULL,
PRIMARY KEY (t)
) ENGINE = InnoDB ;
-- Put a single row:
INSERT INTO truth (t)
VALUES (TRUE) ;
-- Then your table would be:
-- (notice the change to `FLOAT`, to prove that we don't need)
-- (to restrict the solution to a small type)
CREATE TABLE test
( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
age FLOAT NOT NULL,
age_is_allowed BIT -- GENERATED ALWAYS
AS (age >= 0 AND age < 20) -- our CHECK constraint
STORED,
PRIMARY KEY (id),
CONSTRAINT check_age_must_be_non_negative_and_less_than_20
FOREIGN KEY (age_is_allowed)
REFERENCES truth (t)
) ENGINE = InnoDB ;
Пример для версии MySQL 5.7. В MariaDB (версии 5.2+ до 10.1) нам просто нужно изменить синтаксис и объявить столбец PERSISTENT
вместо STORED
. В версии 10.2 также STORED
было добавлено ключевое слово, поэтому приведенный выше пример работает в обоих вариантах (MySQL и MariaDB) для последних версий.
Если мы хотим применить много CHECK
ограничений (что часто встречается во многих проектах), нам просто нужно добавить вычисляемый столбец и внешний ключ для каждого из них. Нам нужна только одна truth
таблица в базе данных. В него должна быть вставлена одна строка, а затем все права на запись удалены.
Однако в последнем MariaDB нам больше не нужно выполнять всю эту акробатику, так как CHECK
ограничения были реализованы. в версии 10.2.1 (альфа-версия: 2016-Jul-04)!
Текущая версия 10.2.2 по-прежнему является бета-версией, но, похоже, эта функция будет доступна в первом стабильном выпуске серии MariaDB 10.2.