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.

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top