2008-12-18 27 views
10

estoy usando SQL Server 2005.valor del campo debe ser único a menos que sea NULL

Tengo un campo que debe contener o bien un valor único o un valor NULL. Creo que debería hacer cumplir esto con un CHECK CONSTRAINT o un TRIGGER for INSERT, UPDATE.

¿Existe una ventaja al usar una restricción aquí sobre un disparador (o viceversa)? ¿A qué se parece semejante restricción/disparador?

¿O hay otra opción más adecuada que no he considerado?

+0

Véanse también las respuestas dadas a esta pregunta: http://stackoverflow.com/questions/191421/how-to- create-a-unique-index-on-a-null-column –

Respuesta

4

Aquí es una forma alternativa de hacerlo con una restricción. Para hacer cumplir esta restricción, necesitará una función que cuente el número de ocurrencias del valor del campo. En su limitación, sólo tiene que asegurarse de que este máximo es 1.

Restricción:

field is null or dbo.fn_count_maximum_of_field(field) < 2 

EDITAR No puedo recordar en este momento - y no puedo comprobarlo, ya sea - si la restricción de comprobación es hecho antes de la inserción/actualización o después. Creo que después de que la inserción/actualización se retrotrae a la falla. Si resulta que estoy equivocado, el 2 anterior debe ser una función Tabla 1.

devuelve un int y utiliza la siguiente selección para derivarla

declare @retVal int 

    select @retVal = max(occurrences) 
    from ( 
     select field, count(*) as occurrences 
     from dbo.tbl 
     where field = @field 
     group by field 
    ) tmp 

Esto debe ser razonablemente rápida si su columna como un índice (no único) en él.

+0

He marcado esta respuesta como correcta porque, aunque la solución de Joe que implica una vista indexada funcionará y es posiblemente más elegante, considero que esta es una forma más "obvia" de restringir los datos en mi tabla y, por lo tanto, es más fácil de mantener. – kristian

+1

esto solo funcionará para modificaciones de una sola fila. Puede fallar para actualizaciones multirrutas: http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/07/01/when-check-constraints-using-udfs-fail-for-multirow-updates.aspx –

+0

Cuando usted dicen que no, quiere decir que erróneamente no permite una actualización que sería legal si todos los cambios ocurrieran al mismo tiempo. No considero que sea tanto un fracaso como una deficiencia del mecanismo. Una falla sería si permitiera que se violara la restricción. El hecho de que previene estados intermedios ilegales así como también estados finales es algo en lo que tiene que trabajar. – tvanfosson

2

En Oracle, una clave única permitirá múltiples NULLs.

En SQL Server 2005, un buen enfoque es hacer las inserciones a través de una vista y deshabilitar las inserciones directas en la tabla.

Here is some sample code.

+1

¿Dónde está el documento técnico que dice que es un buen enfoque? Esto si para DB2 pero aún se aplica: http://www.craigsmullins.com/viewnw.htm – gbn

2

¿Hay una clave principal en esta tabla, tal vez una columna de identidad? Puede crear una clave única compuesta por el campo en el que está aplicando la singularidad, en combinación con la clave principal.

hay una discusión sobre apenas este tipo de problema aquí: http://blog.sqlauthority.com/2008/09/07/sql-server-explanation-about-usage-of-unique-index-and-unique-constraint/

FYI - los índices de SQL Server 2008 presenta filtrado que le permitirían acercarse a esta forma un poco diferente.

+0

No sé quién y por qué downvoted una buena solución. Lo estoy votando, ya que funciona. –

+0

Esta respuesta probablemente fue rechazada debido a la primera sección relacionada con la clave compuesta. Esto permitiría valores nulos duplicados, pero también permitiría valores duplicados en una columna que se supone que contiene solo valores únicos. –

0

Normalmente, un desencadenante le permitirá proporcionar un mensaje más detallado y explicativo que una restricción de verificación, así que los he usado para evitar el juego "qué columna estaba mal" en la depuración.

0

Una restricción es mucho más ligera que un disparador, aunque una restricción única es efectivamente un índice.

Sin embargo, solo se le permite un NULO en una restricción/índice único. Por lo tanto, deberá usar un disparador para detectar duplicados.

Ha sido requested from MS to ignore NULLS, pero SQL 2008 se ha filtrado índices (como se ha mencionado, mientras escribo esto)

6

Creo una vista con un índice que ignora los nulos a través de la cláusula where ... es decir.si inserta nulo en la tabla, a la vista no le importa, pero si inserta un valor no nulo, la vista aplicará la restricción.

create view dbo.UniqueAssetTag with schemabinding 
as 
select asset_tag 
from dbo.equipment 
where asset_tag is not null 

GO 

create unique clustered index ix_UniqueAssetTag 
on UniqueAssetTag(asset_tag) 

GO 

Así que ahora mi mesa del equipo tiene una columna asset_tag que permite múltiples valores nulos, pero sólo valores únicos no nulos.

Nota: Si se utiliza mssql 2000, tendrá que "SET ARITHABORT ON" justo antes de cualquier inserción, actualización o eliminación se lleva a cabo sobre la mesa. Bastante seguro de que esto no es necesario en mssql 2005 en adelante.

3

Puede lograr esto creando una columna calculada y colocando el índice exclusivo en esa columna.

ALTER TABLE MYTABLE 
ADD COL2 AS (CASE WHEN COL1 IS NULL THEN CAST(ID AS NVARCHAR(255)) ELSE COL1 END) 

CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2) 

Esto es suponiendo que el DI es la FC de su mesa y col1 es la columna "único o nula".

La columna calculada (COL2) usará el valor de PK si su columna "única" es nula.

Todavía existe la posibilidad de colisiones entre la columna ID y col1 en el siguiente ejemplo:

ID  COL1 COL2 
1  [NULL] 1 
2  1  1 

Para evitar esto Por lo general crear otra columna calculada que almacena si el valor de col2 proviene de la ID columna o la columna COL1:

ALTER TABLE MYTABLE 
ADD COL3 AS (CASE WHEN COL1 IS NULL THEN 1 ELSE 0 END) 

el índice se deben cambiar a:

CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2, COL3) 

Ahora es el índice en ambas columnas calculadas COL2 y col3 lo que no hay problema:

ID  COL1 COL2 COL3 
1  [NULL] 1  1 
2  1  1  0 
Cuestiones relacionadas