La contrainte CHECK dans MySQL ne fonctionne pas

126

J'ai d'abord créé un tableau comme

CREATE TABLE Customer (
  SD integer CHECK (SD > 0),
  Last_Name varchar (30),
  First_Name varchar(30)
);

puis inséré des valeurs dans cette table

INSERT INTO Customer values ('-2','abc','zz');

MySQL n'affiche pas d'erreur, il a accepté les valeurs.

JohnRaja
la source
Partiellement d'accord. Étant donné que vous avez essayé de l'utiliser, on peut supposer que vous posiez les deux questions. En fait, la réponse que vous avez acceptée explique principalement pourquoi cela ne fonctionne pas.
igorrs
1
Vous pouvez voter sur cette demande de fonctionnalité: bugs.mysql.com/bug.php?id=3464 mais elle n'a reçu aucune attention depuis une décennie.
Jared Beck
11
Vous pouvez utiliser les contraintes CHECK dans MariaDB à partir de la version 10.2.1 .
joanq

Réponses:

140

MySQL 8.0.16 est la première version qui prend en charge les contraintes CHECK.

Lisez https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html

Si vous utilisez MySQL 8.0.15 ou une version antérieure, le manuel de référence MySQL dit:

La CHECKclause est analysée mais ignorée par tous les moteurs de stockage.

Essayez un déclencheur ...

mysql> delimiter //
mysql> CREATE TRIGGER trig_sd_check BEFORE INSERT ON Customer 
    -> FOR EACH ROW 
    -> BEGIN 
    -> IF NEW.SD<0 THEN 
    -> SET NEW.SD=0; 
    -> END IF; 
    -> END
    -> //
mysql> delimiter ;

J'espère que cela pourra aider.

David Kerins
la source
9
Vous trouverez ici comment déclencher une erreur à la place: stackoverflow.com/a/7189396/1144966
petermeissner
41
C'est l'une des nombreuses raisons pour lesquelles j'utiliserai toujours PostgreSQL au lieu de MySQL si j'ai le choix.
Reinderien
5
Je me demande si ce serait un développement de 10 minutes ou 15 minutes dans MySQL pour lancer un avertissement si l'analyseur rencontre une CHECKcontrainte définie. Ahhh, ce serait trop simple ...
gaborsch
75

Malheureusement, MySQL ne prend pas en charge les contraintes de vérification SQL. Vous pouvez les définir dans votre requête DDL pour des raisons de compatibilité, mais ils sont simplement ignorés.

Il existe une alternative simple

Vous pouvez créer BEFORE INSERTet BEFORE UPDATEdéclencher des déclencheurs qui provoquent une erreur ou définissent le champ sur sa valeur par défaut lorsque les exigences des données ne sont pas satisfaites.

Exemple de BEFORE INSERTtravail après MySQL 5.5

DELIMITER $$
CREATE TRIGGER `test_before_insert` BEFORE INSERT ON `Test`
FOR EACH ROW
BEGIN
    IF CHAR_LENGTH( NEW.ID ) < 4 THEN
        SIGNAL SQLSTATE '12345'
            SET MESSAGE_TEXT := 'check constraint on Test.ID failed';
    END IF;
END$$   
DELIMITER ;  

Avant MySQL 5.5, vous deviez provoquer une erreur, par exemple appeler une procédure non définie.

Dans les deux cas, cela provoque une annulation de transaction implicite. MySQL n'autorise pas l'instruction ROLLBACK elle-même dans les procédures et les déclencheurs.

Si vous ne voulez pas annuler la transaction (INSERT / UPDATE devrait passer même avec une "contrainte de vérification" échouée, vous pouvez écraser la valeur en utilisant SET NEW.ID = NULLqui définira l'id sur la valeur par défaut des champs, cela n'a pas vraiment de sens pour un id tho

Edit: Suppression du devis errant.

Concernant l' :=opérateur:

Contrairement à =, l' :=opérateur n'est jamais interprété comme un opérateur de comparaison. Cela signifie que vous pouvez utiliser :=dans n'importe quelle instruction SQL valide (pas seulement dans les instructions SET) pour attribuer une valeur à une variable.

https://dev.mysql.com/doc/refman/5.6/en/assignment-operators.html

Concernant les guillemets d'identifiant backtick:

Le caractère de guillemet identifiant est le backtick («` »)

Si le mode SQL ANSI_QUOTES est activé, il est également permis de citer les identifiants entre guillemets doubles

http://dev.mysql.com/doc/refman/5.6/en/identifiers.html

Michel Feldheim
la source
7
... pas très simple, du moins par rapport à CHECK :(. Coupla tutes: net.tutsplus.com/tutorials/databases/… , sitepoint.com/how-to-create-mysql-triggers
Ben
ugh ça a l'air très encombrant. Je pense que je préfère créer un tuple en python et y vérifier les valeurs au lieu de le mettre.
OzzyTheGiant
Question rapide: pourquoi cela ne fonctionne pas sans définir le DELIMITER?
ddz
52

CHECK les contraintes sont ignorées par MySQL comme expliqué dans un commentaire minuscule dans la documentation: CREATE TABLE

La CHECKclause est analysée mais ignorée par tous les moteurs de stockage.

ypercubeᵀᴹ
la source
2
@thefiloe: Correct, dans d'autres SGBD avec une implémentation correcte des CHECKcontraintes, si l' CHECKévaluation à FALSEalors l'insertion (ou la mise à jour) n'est pas faite et une erreur est provoquée.
ypercubeᵀᴹ
Corrigé dans MariaDB (voir cette réponse stackoverflow.com/a/44333349 ).
Jérôme
@ Jérôme Je sais, j'ai des réponses (plus récentes) qui incluent des améliorations dans ce domaine (il y avait eu d'autres moyens de contourner ce problème, à la fois dans MariaDB et MySQL, avant que MariaDB n'implémente correctement les contraintes CHECK). Ce que je ne suis pas sûr, c'est que je devrais aller modifier toutes mes anciennes réponses!
ypercubeᵀᴹ
Je suppose que mon commentaire avec un lien vers une réponse plus récente est très bien. Ou mieux que rien. J'aurais peut-être dû éditer. Je ne voulais pas vous mettre la pression pour faire quoi que ce soit.
Jérôme
1

Les contraintes de vérification sont prises en charge à partir de la version 8.0.15 (pas encore publiée)

https://bugs.mysql.com/bug.php?id=3464

[23 janv.16: 24] Paul Dubois

Publié par le développeur: corrigé dans la version 8.0.15.

Auparavant, MySQL permettait une forme limitée de syntaxe de contrainte CHECK, mais l'analysait et l'ignorait. MySQL implémente désormais les fonctionnalités principales des contraintes CHECK de table et de colonne, pour tous les moteurs de stockage. Les contraintes sont définies à l'aide des instructions CREATE TABLE et ALTER TABLE.

James
la source
1

Mettez à jour vers MySQL 8.0.16 pour utiliser checks:

Depuis MySQL 8.0.16, CREATE TABLE autorise les fonctionnalités principales des contraintes CHECK de table et de colonne, pour tous les moteurs de stockage. CREATE TABLE autorise la syntaxe de contrainte CHECK suivante, pour les contraintes de table et les contraintes de colonne

Documentation des vérifications MySQL

sdlins
la source
-2

essayez avec set sql_mode = 'STRICT_TRANS_TABLES'OUSET sql_mode='STRICT_ALL_TABLES'

Kanagu
la source
2
qu'actuall n'aide pas (MySQL 5.6) il empêche d'entrer des données de type faux mais pas de saisir des données qui ne répondent pas à la CHECKcontrainte
petermeissner