2008-10-04 12 views
11

¿Cuál es la mejor manera de crear una restricción no nula en MySQL de modo que fieldA y fieldB no puedan ser ambos NULL. No me importa si ninguno de los dos es NULL por sí solo, siempre que el otro campo tenga un valor no NULL. Y si ambos tienen valores no NULL, entonces es aún mejor.O O restricciones no nulas en MySQL

Respuesta

4

MySQL 5.5 introdujo SIGNAL, por lo que ya no necesitamos la columna adicional en la respuesta de Bill Karwin. Bill señaló que también necesita un desencadenador para la actualización, así que lo he incluido también.

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 
2

que he hecho algo similar en SQL Server, no estoy seguro de si va a trabajar directamente en MySQL, pero:

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

Al menos yo creo que es la sintaxis.

Sin embargo, tenga en cuenta que no puede crear restricciones de verificación en las tablas, solo puede verificar las columnas dentro de una misma tabla.

4

Ésta es la sintaxis estándar para una restricción tal, pero MySQL ignora felizmente la restricción después

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

Dado que esta es la sintaxis SQL estándar, esto debería funcionar también con otras bases de datos basadas en SQL. (Definitivamente funciona para PostgreSQL.) – Neall

+0

El manual de MySQL dice: "La cláusula CHECK es analizada pero ignorada por todos los motores de almacenamiento". Lo intenté y es verdad. –

+0

¿Incluso se ignora para las tablas InnoDB? Eso apesta. – Neall

7

@Sklivvz: Prueba con MySQL 5.0.51a, lo encuentro analiza una restricción CHECK, pero no hace cumplir eso. Puedo insertar (NULL, NULL) sin error. Probado tanto MyISAM como InnoDB. El uso posterior de SHOW CREATE TABLE muestra que una restricción CHECK no está en la definición de la tabla, aunque no se proporcionó ningún error cuando definí la tabla.

Esto coincide con MySQL manual que dice: "La cláusula CHECK es analizada pero ignorada por todos los motores de almacenamiento".

Así que para MySQL, tendría que usar un disparador para hacer cumplir esta regla. El único problema es que los desencadenadores MySQL no tienen forma de generar un error o abortar una operación INSERTAR. Una cosa que puede hacer en el desencadenador para causar un error es establecer una columna NOT NULL en 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 

También necesita un disparador similar ANTES DE ACTUALIZAR.

+0

Factura, corrigió mi respuesta en consecuencia, gracias, – Sklivvz

+0

En lugar de usar una columna 'NOT NULL' para forzar un error, puede hacer algo como' SET NEW.FieldA = 1/0' que arrojará un error de división por cero . No es un mensaje de error muy * útil *, pero al menos no tiene que agregar columnas especiales. Realmente me gustaría que MySQL soportara las restricciones adecuadas de 'CHECK', o al menos tuviera una mejor manera de lanzar errores desde los desencadenadores. :( – friedo

+0

@friedo: Como la pregunta del OP era sobre imponer algunas condiciones especiales no nulas, pensé que sería apropiado un mensaje de error de violación nula. Otro truco que puedes hacer en un disparador de MySQL es declarar una variable entera en el disparador y probar para asignarle una cadena. Se genera un mensaje de error que incluye la cadena que utiliza. :) –

7

Esta no es una respuesta directa a su pregunta, pero sí cierta información adicional.

Cuando se trata de varias columnas y comprobar si todos son nulos o uno no es nula, normalmente utilizo COALESCE() - es breve, legible y fácil de mantener si la lista crece:

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 

Esto puede ser usado en tu disparador

Cuestiones relacionadas