Domanda

Qual è il modo migliore per creare un vincolo non NULL in MySQL in modo tale che fieldA e fieldB non possano essere entrambi NULL. Non mi interessa se uno dei due è NULL da solo, purché l'altro campo abbia un valore non NULL. E se entrambi hanno valori non NULL, allora è ancora meglio.

È stato utile?

Soluzione

MySQL 5.5 ha introdotto SIGNAL , quindi non serve più la colonna aggiuntiva nella risposta di Bill Karwin. Bill ha sottolineato che è necessario anche un trigger per l'aggiornamento, quindi l'ho incluso anche io.

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

Altri suggerimenti

Questa non è una risposta direttamente alla tua domanda, ma alcune informazioni aggiuntive.

Quando ho a che fare con più colonne e controllando se tutte sono nulle o una non è nulla, di solito uso COALESCE () - è breve, leggibile e facilmente gestibile se l'elenco cresce:

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

Questo può essere usato nel tuo trigger.

@Sklivvz: testando con MySQL 5.0.51a, trovo che analizzi un vincolo CHECK, ma non lo impone. Posso inserire (NULL, NULL) senza errori. Testato sia MyISAM che InnoDB. Successivamente l'utilizzo di SHOW CREATE TABLE mostra che un vincolo CHECK non è nella definizione della tabella, anche se non è stato fornito alcun errore quando ho definito la tabella.

Questo corrisponde al manuale MySQL che dice: " La clausola CHECK viene analizzata ma ignorata da tutti i motori di archiviazione. "

Quindi per MySQL, dovresti usare un trigger per applicare questa regola. L'unico problema è che i trigger MySQL non hanno modo di generare un errore o interrompere un'operazione INSERT. Una cosa che puoi fare nel trigger per causare un errore è impostare una colonna NOT NULL su 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

È inoltre necessario un trigger simile PRIMA DELL'AGGIORNAMENTO.

Questa è la sintassi standard per un tale vincolo, ma MySQL successivamente ignora beato il vincolo

ALTER TABLE `generic` 
ADD CONSTRAINT myConstraint 
CHECK (
  `FieldA` IS NOT NULL OR 
  `FieldB` IS NOT NULL
) 

Ho fatto qualcosa di simile in SQL Server, non sono sicuro che funzionerà direttamente in MySQL, ma:

ALTER TABLE tableName ADD CONSTRAINT constraintName CHECK ( (fieldA IS NOT NULL) OR (fieldB IS NOT NULL) );

Almeno credo che sia la sintassi.

Tuttavia, tieni presente che non puoi creare vincoli di controllo tra le tabelle, puoi solo controllare le colonne all'interno di una tabella.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top