Soit OU des contraintes non nulles dans MySQL
Question
Quel est le meilleur moyen de créer une contrainte non NULL dans MySQL, de sorte que fieldA et fieldB ne peuvent pas être NULL. Peu m'importe si l'un des deux est NULL par lui-même, tant que l'autre champ a une valeur non NULL. Et si les deux ont des valeurs non NULL, c'est encore mieux.
La solution
MySQL 5.5 a introduit SIGNAL , nous ne le faisons pas. besoin de la colonne supplémentaire dans la réponse de Bill Karwin plus. Bill a souligné que vous aviez également besoin d'un déclencheur pour la mise à jour, donc je l'ai également inclus.
CREATE TABLE foo (
FieldA INT,
FieldB INT
);
DELIMITER //
CREATE TRIGGER InsertFieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
END IF;
END//
CREATE TRIGGER UpdateFieldABNotNull BEFORE UPDATE ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '\'FieldA\' and \'FieldB\' cannot both be null';
END IF;
END//
DELIMITER ;
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error
UPDATE foo SET FieldA = NULL; -- gives error
Autres conseils
Ce n'est pas une réponse directe à votre question, mais quelques informations supplémentaires.
Pour gérer plusieurs colonnes et vérifier si toutes sont nulles ou si l'une d'entre elles est non nulle, j'utilise généralement COALESCE ()
- c'est bref, lisible et facilement maintenable si la liste s'allonge:
COALESCE(a, b, c, d) IS NULL -- True if all are NULL
COALESCE(a, b, c, d) IS NOT NULL -- True if any one is not null
Ceci peut être utilisé dans votre déclencheur.
@Sklivvz: en testant avec MySQL 5.0.51a, je trouve qu'il analyse une contrainte CHECK, mais ne l'applique pas. Je peux insérer (NULL, NULL) sans erreur. Testé MyISAM et InnoDB. Ultérieurement, l’utilisation de SHOW CREATE TABLE montre qu’une contrainte CHECK n’est pas dans la définition de la table, même si aucune erreur n’a été donnée lors de la définition de la table.
Cela correspond au manuel MySQL qui dit: "La clause CHECK est analysée mais ignorée par tous les moteurs de stockage."
Donc, pour MySQL, vous devez utiliser un déclencheur pour appliquer cette règle. Le seul problème est que les déclencheurs MySQL n'ont aucun moyen de générer une erreur ou d'abandonner une opération INSERT. Une des choses que vous pouvez faire dans le déclencheur pour provoquer une erreur consiste à définir une colonne NOT NULL sur NULL.
CREATE TABLE foo (
FieldA INT,
FieldB INT,
FieldA_or_FieldB TINYINT NOT NULL;
);
DELIMITER //
CREATE TRIGGER FieldABNotNull BEFORE INSERT ON foo
FOR EACH ROW BEGIN
IF (NEW.FieldA IS NULL AND NEW.FieldB IS NULL) THEN
SET NEW.FieldA_or_FieldB = NULL;
ELSE
SET NEW.FieldA_or_FieldB = 1;
END IF;
END//
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, 10); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (10, NULL); -- OK
INSERT INTO foo (FieldA, FieldB) VALUES (NULL, NULL); -- gives error
Vous avez également besoin d'un déclencheur similaire AVANT LA MISE À JOUR.
C'est la syntaxe standard pour une telle contrainte, mais MySQL ignore ensuite la contrainte avec bonheur.
ALTER TABLE `generic`
ADD CONSTRAINT myConstraint
CHECK (
`FieldA` IS NOT NULL OR
`FieldB` IS NOT NULL
)
J'ai fait quelque chose de similaire dans SQL Server. Je ne sais pas si cela fonctionnera directement dans MySQL, mais:
ALTER TABLE tableName ADD CONSTRAINT constraintName CHECK ( (fieldA IS NOT NULL) OR (fieldB IS NOT NULL) );
Au moins, je crois que c'est la syntaxe.
Cependant, gardez à l'esprit que vous ne pouvez pas créer de contraintes de vérification sur plusieurs tables, vous pouvez uniquement vérifier les colonnes d'une table.