2012-06-20 11 views
9

Me gustaría definir una restricción entre dos FK numerables en una tabla donde si uno es nulo, el otro necesita un valor, pero ambos no pueden ser nulos y ambos no pueden tener valores La lógica es la tabla derivada hereda los datos de cualquiera de las tablas FK para determinar su tipo. Además, para los puntos de bonificación de diversión, ¿es esta una mala idea?Agregar una restricción XOR de SQL entre dos FK con nulos

+1

[También podría considerar el patrón de tipo super/tipo de subtítulo que se muestra aquí] (http://stackoverflow.com/q/7771869/73226) –

Respuesta

11

Una forma de lograrlo es simplemente escribir lo que "O exclusiva" significa en realidad:

CHECK (
    (FK1 IS NOT NULL AND FK2 IS NULL) 
    OR (FK1 IS NULL AND FK2 IS NOT NULL) 
) 

Sin embargo, si tiene muchos FKs, el método anterior puede convertirse rápidamente en poco manejable, en cuyo caso se puede hacer algo como esto:

CHECK (
    1 = (
     (CASE WHEN FK1 IS NULL THEN 0 ELSE 1 END) 
     + (CASE WHEN FK2 IS NULL THEN 0 ELSE 1 END) 
     + (CASE WHEN FK3 IS NULL THEN 0 ELSE 1 END) 
     + (CASE WHEN FK4 IS NULL THEN 0 ELSE 1 END) 
     ... 
    ) 
) 

por cierto, hay usos legítimos para ese patrón, por ejemplo this one (aunque no aplicable a MS SQL Server debido a la falta de limitaciones diferidos). Si es legítimo en su caso particular, no puedo juzgarlo en base a la información que proporcionó hasta el momento.

+3

más simple: 'CHECK (fk1 IS NULL! = Fk2 IS NULL)' –

+0

@ StephenJ.Fuhry Lamentablemente, MS SQL Server no trata el tipo booleano como un ciudadano de primera clase, por lo que no se aceptará la sintaxis. –

+0

pero funciona en PostgreSQL, que es para lo que lo necesito. gracias por la breve expresión, @ StephenJ.Fuhry. por supuesto, sería mejor tener XOR. dado cuánto material se ha acumulado en el sistema que parece una omisión extraña. – mARK

1

Puede utilizar check constraint:

create table #t (
    a int, 
    b int); 

alter table #t add constraint c1 
check (coalesce(a, b) is not null and a*b is null); 

insert into #t values (1,null); 

insert into #t values (null ,null); 

de reproducción:

The INSERT statement conflicted with the CHECK constraint "c1". 
+1

El 'coalesce (a, b)' devolverá no NULL cuando ** both ** 'a' y' b' no son NULL y CHECK pasará, lo que no debería ocurrir (OP fue explícito de que ambos no pueden tener valores). En otras palabras, el 'insert into #t values ​​(1, 1)' debería fallar. –

+0

seguro. Gracias. Repararé mi respuesta. – danihp

0

camino alternativo es definir esta restricción de comprobación en un procedimiento. Antes de insertar un registro en la tabla derivada, se debe cumplir la restricción. Otra inserción falla o devuelve un error.

Cuestiones relacionadas