¿Alguien puede explicar por qué el SQL Server permite el tercer inserto (etiquetado Query Data) en el siguiente código?¿Por qué mi restricción de verificación no detiene esta inserción nula?
Por lo que yo puedo decir, la restricción de control sólo debe permitir:
Code
es nula ySystem
es nulo.Code
no es nulo ySystem
es1
.
Mi primer pensamiento fue ANSI NULLS
, pero poniéndolos on
o off
hizo ninguna diferencia.
Este es un ejemplo simplificado de un problema más grande que encontramos en nuestra aplicación (el sistema se comprobó en una lista de números - IN(1, 2, etc.)
). Reemplazamos este cheque con una clave externa (en lugar de IN
) y una nueva restricción de verificación que permitía que cualquiera, tanto nulo como ambos, no fuera nulo; haciendo eso evitó el tercer inserto.
IF EXISTS (SELECT * FROM sys.check_constraints WHERE object_id = OBJECT_ID(N'[dbo].[CK_TestCheck]') AND parent_object_id = OBJECT_ID(N'[dbo].[TestCheck]'))
ALTER TABLE [dbo].[TestCheck] DROP CONSTRAINT [CK_TestCheck]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TestCheck]') AND type in (N'U'))
DROP TABLE [dbo].[TestCheck]
GO
SET ANSI_NULLS ON
GO
CREATE TABLE TestCheck(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Code] [varchar](50) NULL,
[System] [tinyint] NULL,
PRIMARY KEY CLUSTERED ([Id] ASC))
GO
ALTER TABLE [dbo].[TestCheck] WITH CHECK ADD CONSTRAINT [CK_TestCheck] CHECK
(
([Code] IS NULL AND [System] IS NULL) --Both null
OR
([Code] IS NOT NULL AND [System] = 1) --Both not null ????
)
GO
ALTER TABLE [dbo].[TestCheck] CHECK CONSTRAINT [CK_TestCheck]
GO
--Good Data
insert TestCheck (Code, [System]) Values(null, null);
insert TestCheck (Code, [System]) Values('123', 1);
--Query Data
insert TestCheck (Code, [System]) Values('123', null);
--Bad data stopped
insert TestCheck (Code, [System]) Values(null, 1);
insert TestCheck (Code, [System]) Values('123', 4);
select * from TestCheck
Where
case when
(
([Code] IS NULL AND [System] IS NULL) --Both null
OR
([Code] IS NOT NULL AND [System] in (1, 2, 3)) --Both not null ????
)
then 0 else 1 end
= 1
No pondría (Falso) entre paréntesis después de indefinido. Definitivamente no es falso. –
@Damien_The_Unbeliever - Sé a qué se refiere, pero lo he agregado entre corchetes en cuanto a lo que 'undefined' hace hacia el resultado final. Agregaré este comentario a la respuesta. –
Pero lo que ha agregado no es verdad. Si el resultado final de la restricción de verificación es 'DESCONOCIDO', entonces se trata igual que si se evaluara como 'VERDADERO' - eso fue lo que sorprendió al OP. –