Qualcuno può spiegare perché il terzo inserto (contrassegnato con dati di query) nel codice sottostante sia consentito da SQL Server?Perché il mio vincolo di controllo non blocca questo inserto nullo?
Per quanto posso dire, il vincolo di controllo dovrebbe consentire solo:
Code
è nullo eSystem
è nullo.Code
non è nullo eSystem
è1
.
Il mio primo pensiero è stato ANSI NULLS
, ma impostandoli on
o off
fatto alcuna differenza.
Questo è un esempio semplificato di un problema più grande che abbiamo riscontrato nella nostra applicazione (il sistema è stato confrontato con un elenco di numeri - IN(1, 2, etc.)
). Abbiamo sostituito questo controllo con una chiave esterna (anziché IN
) e un nuovo vincolo di controllo che consentiva l'uno o l'altro o entrambi non null; fare ciò ha impedito il terzo 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
Non metterei (False) tra parentesi dopo undefined. Non è assolutamente falso. –
@Damien_The_Unbeliever - So cosa intendi ma l'ho aggiunto tra parentesi su cosa "non definito" ha verso il risultato finale. Aggiungerò questo commento alla risposta. –
Ma quello che hai aggiunto non è vero. Se il risultato finale del vincolo di controllo è 'UNKNOWN', allora è trattato come se fosse valutato come' TRUE' - questo è ciò che ha sorpreso l'OP. –