Ou Ou não nulos restrições no MySQL
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.
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.