Dav*_*haw 13 sql-server sql-server-2008-r2
谁能解释为什么SQL Server允许下面代码中的第三个插入(标记为Query Data)?
据我所知,检查约束应该只允许:
Code为null且System为null.Code不是null并且System是1.我的第一个想法是ANSI NULLS,但设定它们on或off没有任何区别.
这是我们在应用程序中发现的更大问题的简化示例(系统是根据数字列表进行检查的 - IN(1, 2, etc.)).我们用一个外键(而不是IN)和一个新的检查约束替换了这个检查,这个约束允许null或者两者都不为null; 这样做阻止了第三次插入.
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
Run Code Online (Sandbox Code Playgroud)
Dam*_*ver 16
欢迎使用SQL精彩的三值逻辑.正如你可能会或可能不知道,任何标准比较的结果null是不是TRUE,或者FALSE,但是UNKNOWN.
在一个WHERE条款中,整个条款必须评估为TRUE.
在CHECK约束中,整个约束必须评估为不FALSE.
所以,我们有:
([Code] IS NULL AND [System] IS NULL) --Both null
OR
([Code] IS NOT NULL AND [System] = 1) --Both not null ????
Run Code Online (Sandbox Code Playgroud)
哪个(对于查询数据):
(FALSE AND TRUE)
OR
(TRUE AND UNKNOWN)
Run Code Online (Sandbox Code Playgroud)
任何UNKNOWN一方或另一方的运算符都评估为UNKNOWN,所以总体结果是UNKNOWN.哪个不是FALSE,因此评估检查约束是成功的.
如果你不想System为null,那么如果你把它作为一个额外的显式要求添加它,它对我来说是最清楚的.
([Code] IS NULL AND [System] IS NULL) --Both null
OR
([Code] IS NOT NULL AND [System] IS NOT NULL AND [System] = 1) --Both not null ????
Run Code Online (Sandbox Code Playgroud)
这似乎是一点点奇怪的是,这个被定义的方式,但它与其他约束的工作方式一致 - 一个外键约束可能具有空列如,而如果这些列是空的,也不必是引用表中的匹配行.
Lie*_*ers 12
评估值的当前约束的结果123, NULL是Undefined.
([Code] IS NULL AND [System] IS NULL) 评估为 False([Code] IS NOT NULL AND [System] IN (1, 2, 3)) 评估为 Undefined结果是 Undefined
CHECK约束拒绝评估为FALSE的值.因为null值计算为UNKNOWN,所以它们在表达式中的存在可能会覆盖约束.
你应该改变你的支票[System] IN (1, 2, 3)来ISNULL([System], 0) IN (1, 2, 3).
然后您的检查约束变为
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 ISNULL([System], 0) IN (1, 2, 3)) --Both not null ????
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10246 次 |
| 最近记录: |