2011-01-26 10 views
18

Tengo una columna bit IsDefault. Solo una fila de datos dentro de la tabla puede tener esta columna de bits establecida en 1, todas las demás deben ser 0.SQL Server restricción de columna de bits, 1 fila = 1, todos los demás 0

¿Cómo puedo hacer cumplir esto?

+6

¿Has considerado una arquitectura alternativa? Digamos que tiene una referencia en otro lugar que apunta a la fila "predeterminada". –

+1

¿qué versión de SQL Server, por favor? – gbn

+0

¡Qué gran pregunta! Solo estoy escribiendo esto para expresar mis otros 99 puntos de agradecimiento. –

Respuesta

30

Todas las versiones:

  • gatillo
  • vista indizada
  • procedimiento almacenado (por ejemplo, prueba de escritura)

SQL Server 2008: a filtered index

CREATE UNIQUE INDEX IX_foo ON bar (MyBitCol) WHERE MyBitCol = 1 
+0

Bueno, eso ciertamente les impediría guardar múltiples registros con un valor predeterminado. – NotMe

+1

Los índices filtrados requieren ANSI PADDING ON. Entonces ejecute 'SET ANSI PADDING ON' antes de crear un índice filtrado. – naXa

1

Usted podría aplicar un En lugar de Inserte el disparador y verifique el valor cuando ingrese.

Create Trigger TRG_MyTrigger 
on MyTable 
Instead of Insert 
as 
Begin 

    --Check to see if the row is marked as active.... 
    If Exists(Select * from inserted where IsDefault= 1) 
    Begin 
    Update Table Set IsDefault=0 where ID= (select ID from inserted); 

    insert into Table(Columns) 
    select Columns from inserted 
    End 

End 

Como alternativa, puede aplicar una restricción única en la columna.

16

Asumiendo que su PK es una sola, columna numérica, se puede agregar una columna calculada a su mesa:

ALTER TABLE YourTable 
    ADD IsDefaultCheck AS CASE IsDefault 
    WHEN 1 THEN -1 
    WHEN 0 THEN YourPK 
    END 

A continuación, cree un índice único en la columna calculada.

CREATE UNIQUE INDEX IX_DefaultCheck ON YourTable(IsDefaultCheck) 
+0

+1 nunca pensé en esto. Una solución de DRI sin un índice filtrado – gbn

+0

+ 1 buena solución. –

+0

Esta es la mejor solución, en mi opinión, ya que no implica desencadenantes. De hecho, todo lo provisto en esta solución probablemente pueda implementarse en línea en la definición original de la tabla. – Tripartio

2

creo que el disparador es la mejor idea si desea cambiar el antiguo registro por defecto a 0 al insertar/actualizar uno nuevo y si usted quiere asegurarse de que un registro siempre tiene ese valor (es decir, si elimina el registro con el valor que le asignaría a un registro diferente). Tendría que decidir sobre las reglas para hacerlo. Estos desencadenantes pueden ser complicados porque debe contabilizar múltiples registros en las tablas insertadas y eliminadas. Entonces, si 3 registros en un lote intentan actualizarse para convertirse en el registro predeterminado, ¿cuál gana?

Si desea asegurarse de que el registro predeterminado nunca cambia cuando alguien más intenta cambiarlo, el índice filtrado es una buena idea.

1

La respuesta aceptada a la siguiente pregunta es a la vez interesante y relevante:

Constraint for only one record marked as default

"Pero los graves relacionales gente le dirá que esta información debe ser sólo en otra mesa."

Disponga de una tabla separada de 1 fila que le indica qué registro es 'predeterminado'. Anon tocó esto en su comentario.

Creo que este es el mejor enfoque: simple, limpio & no requiere una solución esotérica 'inteligente' propensa a errores o malentendidos posteriores. Incluso puede soltar la columna IsDefualt.