Quiero tener una restricción única en una columna que voy a llenar con GUID. Sin embargo, mis datos contienen valores nulos para estas columnas. ¿Cómo creo la restricción que permite múltiples valores nulos?
Aquí hay un escenario de ejemplo . Considere este esquema:
CREATE TABLE People (
Id INT CONSTRAINT PK_MyTable PRIMARY KEY IDENTITY,
Name NVARCHAR(250) NOT NULL,
LibraryCardId UNIQUEIDENTIFIER NULL,
CONSTRAINT UQ_People_LibraryCardId UNIQUE (LibraryCardId)
)
Luego vea este código para lo que estoy tratando de lograr:
-- This works fine:
INSERT INTO People (Name, LibraryCardId)
VALUES ('John Doe', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
-- This also works fine, obviously:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Marie Doe', 'BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB');
-- This would *correctly* fail:
--INSERT INTO People (Name, LibraryCardId)
--VALUES ('John Doe the Second', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
-- This works fine this one first time:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Richard Roe', NULL);
-- THE PROBLEM: This fails even though I'd like to be able to do this:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Marcus Roe', NULL);
La declaración final falla con un mensaje:
Infracción de la restricción ÚNICA CLAVE 'UQ_People_LibraryCardId'. No se puede insertar una clave duplicada en el objeto 'dbo.People'.
¿Cómo puedo cambiar mi esquema y / o restricción de unicidad para que permita múltiples NULL
valores, sin dejar de verificar la unicidad en los datos reales?
sql-server
tsql
Stuart
fuente
fuente
null
no es un valor sino la ausencia de valor. Según el estándar SQL,null
no se considera igual anull
. Entonces, ¿por qué múltiplesnull
debería ser una violación de unicidad?Respuestas:
SQL Server 2008 +
Puede crear un índice único que acepte múltiples NULL con una
WHERE
cláusula. Ver la respuesta a continuación .Antes de SQL Server 2008
No puede crear una restricción ÚNICA y permitir NULLs. Debe establecer un valor predeterminado de NEWID ().
Actualice los valores existentes a NEWID () donde NULL antes de crear la restricción UNIQUE.
fuente
Lo que está buscando es, de hecho, parte de los estándares ANSI SQL: 92, SQL: 1999 y SQL: 2003, es decir, una restricción ÚNICA debe rechazar valores duplicados que no sean NULL pero aceptar múltiples valores NULL.
Sin embargo, en el mundo de Microsoft de SQL Server, se permite un solo NULL pero no se admiten varios NULL ...
En SQL Server 2008 , puede definir un índice filtrado único basado en un predicado que excluya NULL:
En versiones anteriores, puede recurrir a VIEWS con un predicado NOT NULL para aplicar la restricción.
fuente
SQL Server 2008 y hasta
Simplemente filtre un índice único:
En versiones inferiores, todavía no se requiere una vista materializada
Para SQL Server 2005 y versiones anteriores, puede hacerlo sin una vista. Acabo de agregar una restricción única como la que estás pidiendo a una de mis tablas. Dado que quiero unicidad en la columna
SamAccountName
, pero quiero permitir múltiples NULL, utilicé una columna materializada en lugar de una vista materializada:Simplemente tiene que poner algo en la columna calculada que se garantizará como único en toda la tabla cuando la columna única deseada real sea NULL. En este caso,
PartyID
es una columna de identidad y ser numérico nunca coincidirá con ningunaSamAccountName
, por lo que funcionó para mí. Puede probar su propio método: asegúrese de comprender el dominio de sus datos para que no haya posibilidad de intersección con datos reales. Eso podría ser tan simple como anteponer un carácter diferenciador como este:Incluso si
PartyID
algún día se volviera no numérico y pudiera coincidir con unSamAccountName
, ahora no importará.Tenga en cuenta que la presencia de un índice que incluye la columna calculada hace que implícitamente cada resultado de la expresión se guarde en el disco con los otros datos de la tabla, lo que NO requiere espacio en disco adicional.
Tenga en cuenta que si no desea un índice, aún puede guardar la CPU haciendo que la expresión se calcule previamente en el disco agregando la palabra clave
PERSISTED
al final de la definición de expresión de columna.En SQL Server 2008 y versiones posteriores, ¡definitivamente use la solución filtrada si es posible!
Controversia
Tenga en cuenta que algunos profesionales de bases de datos verán esto como un caso de "NULL sustitutos", que definitivamente tienen problemas (principalmente debido a problemas relacionados con el intento de determinar cuándo algo es un valor real o un valor sustituto para los datos faltantes) ; también puede haber problemas con el número de valores sustitutos no NULL que se multiplican como locos).
Sin embargo, creo que este caso es diferente. La columna calculada que estoy agregando nunca se usará para determinar nada. No tiene ningún significado en sí mismo y no codifica ninguna información que no se encuentre por separado en otras columnas definidas correctamente. Nunca debe seleccionarse o usarse.
Por lo tanto, mi historia es que este no es un NULL sustituto, ¡y lo estoy cumpliendo! Dado que en realidad no queremos el valor no NULL para ningún otro propósito que no sea engañar al
UNIQUE
índice para que ignore los NULL, nuestro caso de uso no tiene ninguno de los problemas que surgen con la creación NULL sustituta normal.Dicho todo esto, no tengo ningún problema con el uso de una vista indexada, pero trae algunos problemas, como el requisito de usar
SCHEMABINDING
. Diviértase agregando una nueva columna a su tabla base (como mínimo, tendrá que soltar el índice y luego soltar la vista o modificar la vista para que no esté vinculada al esquema). Consulte la lista completa (larga) de requisitos para crear una vista indizada en SQL Server (2005) (también versiones posteriores), (2000) .Actualizar
Si su columna es numérica, puede existir el desafío de garantizar que el uso exclusivo de la restricción
Coalesce
no provoque colisiones. En ese caso, hay algunas opciones. Una podría ser utilizar un número negativo, poner los "NULL sustitutos" solo en el rango negativo y los "valores reales" solo en el rango positivo. Alternativamente, se podría usar el siguiente patrón. En la tablaIssue
(dondeIssueID
está elPRIMARY KEY
), puede haber o no unTicketID
, pero si hay uno, debe ser único.Si el IssueID 1 tiene el ticket 123, la
UNIQUE
restricción estará en los valores (123, NULL). Si IssueID 2 no tiene ticket, estará encendido (NULL, 2). Algún pensamiento mostrará que esta restricción no se puede duplicar para ninguna fila de la tabla y aún permite múltiples NULL.fuente
Para las personas que usan Microsoft SQL Server Manager y desean crear un índice único pero anulable, puede crear su índice único como lo haría normalmente en sus Propiedades de índice para su nuevo índice, seleccione "Filtro" en el panel izquierdo, luego ingrese su filtro (que es su cláusula where). Debería leer algo como esto:
Esto funciona con MSSQL 2012
fuente
Cuando apliqué el índice único a continuación:
cada actualización e inserción no nula fallaron con el siguiente error:
Encontré esto en MSDN
Así que para que esto funcione correctamente hice esto
Creo que es posible configurar esta opción en código usando
pero no he probado esto
fuente
Cree una vista que seleccione solo no
NULL
columnas y creeUNIQUE INDEX
en la vista:Tenga en cuenta que deberá realizar
INSERT
's yUPDATE
' s en la vista en lugar de en la tabla.Puede hacerlo con un
INSTEAD OF
disparador:fuente
También se puede hacer en el diseñador
Haga clic derecho en el Índice> Propiedades para obtener esta ventana
fuente
Es posible crear una restricción única en una Vista indizada en clúster
Puede crear la Vista de esta manera:
y la restricción única como esta:
fuente
¿Quizás considere un "
INSTEAD OF
" disparador y haga la verificación usted mismo? Con un índice no agrupado (no exclusivo) en la columna para habilitar la búsqueda.fuente
Como se indicó anteriormente, SQL Server no implementa el estándar ANSI cuando se trata de eso
UNIQUE CONSTRAINT
. Hay un boleto en Microsoft Connect para esto desde 2007. Como se sugiere aquí y aquí, las mejores opciones a partir de hoy son usar un índice filtrado como se indica en otra respuesta o una columna calculada, por ejemplo:fuente
Puedes crear un INSTEAD OF OF desencadenador para verificar condiciones específicas y errores si se cumplen. Crear un índice puede ser costoso en tablas más grandes.
Aquí hay un ejemplo:
fuente
No puede hacer esto con una
UNIQUE
restricción, pero puede hacerlo en un disparador.fuente
fuente
este código si realiza un formulario de registro con textBox y utiliza insert y ur textBox está vacío y hace clic en el botón Enviar.
fuente