Pergunta

Qual é a melhor maneira de criar uma restrição de não-NULL no MySQL tal que fieldA e fieldB não pode ser tanto NULL. Eu não me importo se qualquer um é NULL, por si só, apenas enquanto o outro campo tem um valor diferente de NULL. E se ambos têm valores não-NULL, então é ainda melhor.

Foi útil?

Solução

MySQL 5.5 introduziu SINAL , então não fazer precisa a coluna extra na resposta de Bill Karwin mais. Bill apontou também precisa de gatilho para atualização por isso incluímos isso também.

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

Outras dicas

Esta não é uma resposta directa à sua pergunta, mas algumas informações adicionais.

Ao lidar com várias colunas e verificar se todos são nulo ou não é nulo, eu normalmente usam COALESCE() - é breve, legível e de fácil manutenção, se a lista 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

Isso pode ser usado em seu gatilho.

@Sklivvz: Testes com MySQL 5.0.51a, acho que ele analisa uma restrição CHECK, mas não aplicá-la. Posso inserir (NULL, NULL) com nenhum erro. Testado tanto MyISAM e InnoDB. Posteriormente usando SHOW CREATE TABLE mostra que uma restrição CHECK não é na definição da tabela, mesmo que nenhum erro foi dado quando eu definida a mesa.

Isto combina MySQL manual, que diz: "A cláusula WITH CHECK é analisado, mas ignorado por todos os mecanismos de armazenamento".

Assim, para MySQL, você teria que usar um gatilho para fazer cumprir esta regra. O único problema é que gatilhos MySQL não têm nenhuma maneira de levantar um erro ou abortar uma operação INSERT. Uma coisa que você pode fazer no gatilho para causar um erro é definir uma coluna NOT NULL para 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

Você também precisa de um gatilho semelhante Antes UPDATE.

Esta é a sintaxe padrão para tal restrição um, mas MySQL alegremente ignora a restrição depois

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

Eu tenho feito algo semelhante no SQL Server, eu não tenho certeza se ele vai trabalhar diretamente no MySQL, mas:

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

Pelo menos eu acredito que é a sintaxe.

No entanto, tenha em mente que você não pode criar restrições de verificação em tabelas, você só pode verificar as colunas dentro de uma tabela.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top