Outre la belle solution de déclenchement de @Rolando, il existe une autre solution à ce problème dans MySQL (jusqu'à ce que les CHECK
contraintes soient mises en œuvre).
Comment émuler certaines CHECK
contraintes dans MySQL
Donc, si vous préférez les contraintes d'intégrité référentielle et que vous souhaitez éviter les déclencheurs (en raison des problèmes dans MySQL lorsque vous avez les deux dans vos tables), vous pouvez utiliser une autre petite table de référence:
CREATE TABLE age_allowed
( age TINYINT UNSIGNED NOT NULL
, PRIMARY KEY (age)
) ENGINE = InnoDB ;
Remplissez-le avec 20 lignes:
INSERT INTO age_allowed
(age)
VALUES
(0), (1), (2), (3), ..., (19) ;
Votre table serait alors:
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 ;
Vous devrez supprimer l'accès en écriture au age_allowed
table, pour éviter d'ajouter ou de supprimer accidentellement des lignes.
Cette astuce ne fonctionnera FLOAT
malheureusement pas avec les colonnes de type de données (trop de valeurs entre 0.0
et 20.0
).
Comment émuler des CHECK
contraintes arbitraires dans MySQL (5.7) et MariaDB (de 5.2 à 10.1)
Depuis que MariaDB a ajouté des colonnes calculées dans leur version 5.2 ( version GA: 2010-11-10 ) et MySQL dans 5.7 (version GA: 2015-10-21 ) - qu'ils les appellent VIRTUAL
et GENERATED
respectivement - qui peuvent être persistées, c'est-à-dire stockées dans le table - ils les appellent PERSISTENT
et STORED
respectivement - nous pouvons les utiliser pour simplifier la solution ci-dessus et encore mieux, l' étendre pour émuler / appliquer des CHECK
contraintes arbitraires ):
Comme ci-dessus, nous aurons besoin d'une table d'aide mais avec une seule ligne cette fois qui agira comme une table "d'ancrage". Encore mieux, ce tableau peut être utilisé pour n'importe quel nombre de CHECK
contraintes.
Nous ajoutons ensuite une colonne calculée qui évalue à TRUE
/ FALSE
/ UNKNOWN
, exactement comme le CHECK
ferait une contrainte - mais cette colonne a une FOREIGN KEY
contrainte à notre table d'ancrage. Si la condition / colonne est évaluée à FALSE
pour certaines lignes, les lignes sont rejetées, en raison du FK.
Si la condition / colonne est évaluée à TRUE
ou UNKNOWN
( NULL
), les lignes ne sont pas rejetées, exactement comme cela devrait se produire avec des CHECK
contraintes:
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 ;
L'exemple concerne la version MySQL 5.7. Dans MariaDB (versions 5.2+ à 10.1), il suffit de modifier la syntaxe et de déclarer la colonne comme PERSISTENT
au lieu de STORED
. Dans la version 10.2, le STORED
mot - clé a également été ajouté, donc l'exemple ci-dessus fonctionne dans les deux versions (MySQL et MariaDB) pour les dernières versions.
Si nous voulons appliquer de nombreuses CHECK
contraintes (ce qui est courant dans de nombreuses conceptions), il nous suffit d'ajouter une colonne calculée et une clé étrangère pour chacune d'entre elles. Nous n'avons besoin que d'une truth
table dans la base de données. Il doit avoir une ligne insérée, puis tous les accès en écriture supprimés.
Dans la dernière MariaDB cependant, nous n'avons plus à effectuer toutes ces acrobaties, car les CHECK
contraintes ont été implémentées dans la version 10.2.1 (version alpha: 2016-juil-04)!
La version 10.2.2 actuelle est toujours une version bêta mais il semble que la fonctionnalité sera disponible dans la première version stable de la série MariaDB 10.2.