Oprócz fajnego rozwiązania wyzwalającego autorstwa @Rolando istnieje jeszcze jedno obejście tego problemu w MySQL (dopóki CHECK
ograniczenia nie zostaną zaimplementowane).
Jak emulować niektóre CHECK
ograniczenia w MySQL
Tak więc, jeśli wolisz ograniczenia spójności referencyjnej i chcesz uniknąć wyzwalaczy (z powodu problemów w MySQL, gdy masz oba w swoich tabelach), możesz użyć innej małej tabeli referencyjnej:
CREATE TABLE age_allowed
( age TINYINT UNSIGNED NOT NULL
, PRIMARY KEY (age)
) ENGINE = InnoDB ;
Wypełnij go 20 rzędami:
INSERT INTO age_allowed
(age)
VALUES
(0), (1), (2), (3), ..., (19) ;
Wtedy twój stół będzie:
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 ;
Musisz usunąć dostęp do zapisu w age_allowed
tabeli, aby uniknąć przypadkowego dodania lub usunięcia wierszy.
Ta sztuczka nie będzie działać z FLOAT
kolumnami typu danych, niestety (zbyt wiele wartości pomiędzy 0.0
i 20.0
).
Jak emulować arbitralne CHECK
ograniczenia w MySQL (5.7) i MariaDB (od 5.2 do 10.1)
Od MariaDB dodania kolumny obliczane w wersji 5.2 (GA wydanie: 2010-11-10 ) oraz MySQL 5.7 (GA wydanie: 2015-10-21 ) - który nazywają je VIRTUAL
i GENERATED
odpowiednio - które mogą być utrwalone, tj przechowywane w tabela - nazywają je PERSISTENT
i STORED
odpowiednio - możemy z nich korzystać, aby uprościć powyższe rozwiązanie, a nawet lepiej, przedłużyć go naśladować / egzekwować arbitralnych CHECK
ograniczeń ):
Jak wyżej, potrzebujemy tabeli pomocy, ale tym razem z jednym rzędem, który będzie działał jako tabela „kotwicy”. Co więcej, ta tabela może być używana do dowolnej liczby CHECK
ograniczeń.
Następnie dodajemy kolumnę obliczeniową, która ocenia do TRUE
/ FALSE
/ UNKNOWN
, dokładnie tak, jak CHECK
wiązałoby to ograniczenie - ale ta kolumna ma FOREIGN KEY
ograniczenie do naszej tabeli zakotwiczenia. Jeśli warunek / kolumna ma wartość FALSE
dla niektórych wierszy, wiersze są odrzucane z powodu FK.
Jeśli warunek / kolumna ma wartość TRUE
lub UNKNOWN
( NULL
), wiersze nie są odrzucane, dokładnie tak jak powinno być w przypadku CHECK
ograniczeń:
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 ;
Przykład dotyczy wersji MySQL 5.7. W MariaDB (wersje 5.2+ do 10.1) wystarczy zmodyfikować składnię i zadeklarować kolumnę jako PERSISTENT
zamiast STORED
. W wersji 10.2 STORED
dodano również słowo kluczowe, więc powyższy przykład działa w obu wersjach (MySQL i MariaDB) dla najnowszych wersji.
Jeśli chcemy wymusić wiele CHECK
ograniczeń (co jest powszechne w wielu projektach), musimy po prostu dodać obliczoną kolumnę i klucz obcy dla każdego z nich. Potrzebujemy tylko jednej truth
tabeli w bazie danych. Powinien mieć wstawiony jeden wiersz, a następnie usunięty cały dostęp do zapisu.
W najnowszej wersji MariaDB nie musimy jednak wykonywać tych wszystkich akrobacji, ponieważ CHECK
ograniczenia zostały zaimplementowane w wersji 10.2.1 (wydanie alfa: 2016-lipiec-04)!
Obecna wersja 10.2.2 jest wciąż wersją beta, ale wydaje się, że funkcja będzie dostępna w pierwszym stabilnym wydaniu serii MariaDB 10.2.