Neben der netten Trigger-Lösung von @Rolando gibt es in MySQL eine weitere Problemumgehung (bis CHECK
Einschränkungen implementiert sind).
So emulieren Sie einige CHECK
Einschränkungen in MySQL
Wenn Sie also referenzielle Integritätsbeschränkungen bevorzugen und Trigger vermeiden möchten (aufgrund der Probleme in MySQL, wenn Sie beide in Ihren Tabellen haben), können Sie eine andere kleine Referenztabelle verwenden:
CREATE TABLE age_allowed
( age TINYINT UNSIGNED NOT NULL
, PRIMARY KEY (age)
) ENGINE = InnoDB ;
Fülle es mit 20 Zeilen:
INSERT INTO age_allowed
(age)
VALUES
(0), (1), (2), (3), ..., (19) ;
Dann wäre Ihr Tisch:
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 ;
Sie müssen den Schreibzugriff auf die age_allowed
Tabelle entfernen, um ein versehentliches Hinzufügen oder Entfernen von Zeilen zu vermeiden.
Dieser Trick funktioniert FLOAT
leider nicht mit Datentypspalten (zu viele Werte zwischen 0.0
und 20.0
).
Wie man willkürliche CHECK
Einschränkungen in MySQL (5.7) und MariaDB (von 5.2 bis 10.1) emuliert
Da MariaDB hinzugefügt berechnete Spalten in ihrer Version 5.2 (GA - Version: 2010-11-10 ) und MySQL in 5.7 (GA - Version: 2015.10.21 ) - was sie sie nennen VIRTUAL
und GENERATED
jeweils - , die beibehalten werden können, dh in dem gespeicherte Tisch - sie nennen sie PERSISTENT
und STORED
jeweils - wir können sie die obige Lösung zu vereinfachen , verwenden und noch besser, erweitern sie zu emulieren / willkürliche Durchsetzung CHECK
Einschränkungen ):
Wie oben benötigen wir eine Hilfetabelle, diesmal jedoch mit einer einzelnen Zeile, die als "Ankertabelle" fungiert. Noch besser ist, dass diese Tabelle für eine beliebige Anzahl von verwendet werden kannCHECK
Einschränkungen verwendet werden kann.
Wir fügen dann eine berechnete Spalte , dass auswertet , um entweder TRUE
/ FALSE
/ UNKNOWN
, genau wie ein CHECK
Zwang würde - aber diese Spalte hat eineFOREIGN KEY
Einschränkung unserer Ankertabelle. Wenn die Bedingung / Spalte FALSE
für einige Zeilen mit " 0" bewertet wird , werden die Zeilen aufgrund der FK zurückgewiesen.
Wenn die Bedingung / Spalte als TRUE
oder UNKNOWN
( NULL
) ausgewertet wird , werden die Zeilen nicht genau so abgelehnt, wie es mit CHECK
Einschränkungen geschehen sollte :
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 ;
Das Beispiel ist für die MySQL 5.7-Version. In MariaDB (Versionen 5.2+ bis 10.1), wir müssen nur die Syntax ändern und erklären , die Spalte als PERSISTENT
stattSTORED
. In Version 10.2 wurde das STORED
Schlüsselwort ebenfalls hinzugefügt, sodass das obige Beispiel in beiden Varianten (MySQL und MariaDB) für die neuesten Versionen funktioniert.
Wenn wir viele CHECK
Einschränkungen erzwingen möchten (was in vielen Entwürfen üblich ist), müssen wir nur eine berechnete Spalte und einen Fremdschlüssel für jeden von ihnen hinzufügen. Wir brauchen nur einentruth
Tabelle in der Datenbank. Es sollte eine Zeile eingefügt und dann alle Schreibrechte entfernt werden.
In der neuesten MariaDB müssen wir diese Akrobatik jedoch nicht mehr ausführen, da CHECK
Einschränkungen in Version 10.2.1 (Alpha-Release: 2016-Jul-04) implementiert wurden !
Die aktuelle 10.2.2-Version ist noch eine Beta-Version, aber es scheint, dass die Funktion in der ersten stabilen Version der MariaDB 10.2-Serie verfügbar sein wird.