2010-10-04 4 views
1

Dans ma table MySQL, chaque colonne peut être NULL, mais il doit y avoir au moins une colonne avec une valeur non-NULL. Pour l'instant, je suis en train d'encapsuler une instruction insert dans une procédure stockée qui empêche l'insertion de toutes les lignes NULL, mais cela n'empêche personne d'utiliser des instructions INSERT natives, contournant ma procédure wrapper.MySQL: comment empêcher l'insertion d'une ligne avec toutes les colonnes = NULL?

Existe-t-il une manière «native» de définir la table avec cette contrainte?

Répondre

2

Puisque MySQL n'applique pas les contraintes de vérification, vous pouvez en émuler une avec un déclencheur. Je suggérerais vérifier cet article MySQL Forge:

L'idée est de déplacer votre logique de contrôle à un déclencheur. Si la vérification échoue, appelez une procédure stockée qui échoue en levant une violation de clé unique. Cela nous permet de renvoyer un message d'erreur descriptif au client.

Votre déclencheur sera probablement quelque chose comme ceci:

DELIMITER $$ 
CREATE TRIGGER check_not_all_null BEFORE INSERT ON your_table FOR EACH ROW 
BEGIN 
    IF COALESCE(field_1, field_2, field_3) IS NOT NULL THEN 
     CALL fail('All fields cannot be null'); 
    END IF; 
END $$ 
DELIMITER ; 

Nous devons faire le nécessaire fail sproc soulever une violation de clé unique afin d'avoir le INSERT avorté lorsque la vérification échoue. L'article ci-dessus mentionné suggère la création d'une table de mémoire définie comme suit:

CREATE TABLE `Error` (                
    `ErrorGID` int(10) unsigned NOT NULL auto_increment,        
    `Message` varchar(128) default NULL,         
    `Created` timestamp NOT NULL default CURRENT_TIMESTAMP 
       ON UPDATE CURRENT_TIMESTAMP,   
    PRIMARY KEY (`ErrorGID`),             
    UNIQUE KEY `MessageIndex` (`Message`) 
) ENGINE=MEMORY DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED 

Alors le fail sproc pourrait être mis en œuvre comme suit:

DELIMITER $$ 
CREATE PROCEDURE `fail`(_message VARCHAR(128)) 
BEGIN 
    INSERT INTO error (message) VALUES (_message); 
    INSERT INTO error (message) VALUES (_message); 
END$$ 
DELIMITER ; 

Le double INSERT veillera à ce que la violation clé unique est soulevée. Si le même message existe déjà dans la table, la violation sera levée sur le premier INSERT, mais cela n'a pas d'importance tant qu'il échoue.

On peut essayer le fail sproc de la ligne de commande:

mysql> CALL fail('All fields cannot be null'); 
ERROR 1062 (23000): Duplicate entry 'All fields cannot be null' for key 2 

Les bonnes nouvelles sont que nous revenions un message d'erreur lisible. Cependant, nous ne récupérons pas le code d'erreur correct, et nous n'avons pas vraiment de "doublon". Il s'agit évidemment d'une limitation de cette méthode, notamment lors de la mise à jour ou de l'insertion d'enregistrements dans une procédure qui utilise la gestion des erreurs, notamment en traitant spécifiquement l'erreur 1062 Duplicate Entry.

+0

WOW! Merci beaucoup pour cette réponse détaillée !! :-) – ssc

3

octroyer des autorisations d'exécution uniquement pour que les utilisateurs ou l'utilisateur de votre application puissent uniquement appeler des procédures stockées!

2

ajouter simple vérification contrainte

CHECK(COALESCE(Field1, Field2, ... FieldN) IS NOT NULL) 

MISE À JOUR:

Constaté que MySQL ne supporte pas contrainte de vérification (analyser, mais ignorer), on est possible solution: en utilisant la gâchette (regarder vers http://db4free.blogspot.com/2006/01/emulating-check-constraints.html)

+0

Les contraintes de vérification ne sont pas supportées dans toutes les versions de MySQL, malheureusement :( –

+0

@Daniel, merci beaucoup a été très surpris, vérifiez parsé, mais pas utilisé. :( –

Questions connexes