当我使用下面的测试脚本创建检查约束时,仍然允许违反约束的数据进入表中,并且约束仍显示为受信任。
我意识到检查约束没有正确检查NULL(它包括column = null
而不是column IS null
),但我仍然希望SQL Server不允许'ASDF','3 '或NULL值,因为检查条件对这些值的计算结果为false。有人可以解释为什么这个检查约束允许以下值:NULL,'3','ASDF'?
如果我将约束条件更改为(checkMe is null or checkMe = '1' or checkMe = '2')
,则它会按预期工作。
SQL Server版本:Microsoft SQL Server 2008 R2(SP2) - 10.50.4000.0(X64)
CREATE TABLE dbo.testCheck(checkMe varchar(50));
go
将数据插入表格
INSERT INTO dbo.testCheck(checkMe)
VALUES ('1'),('2'),(NULL),('3');
GO
添加约束,并进行检查,以便检查现有数据。我希望NULL和'3'都违反了这个检查,但它以某种方式成功了。
ALTER TABLE dbo.testCheck WITH CHECK
ADD CONSTRAINT ck_testCheck
CHECK (checkMe = null or checkMe = '1' or checkMe = '2');
GO
在添加检查约束后尝试插入无效数据...这是否成功?
INSERT INTO dbo.testCheck(checkMe) VALUES('ASDF');
GO
显示该表包含无效数据,并且此约束被标记为受信任,这意味着表中的所有数据都已根据约束进行验证
SELECT *
--this is the same logic as in the check constraint, shows 3 rows that do not pass
, checkConstraintLogic = case when (checkMe = null or checkMe = '1' or checkMe = '2') then 'PASS' else 'FAIL' end
FROM dbo.testCheck;
go
SELECT parentObject = isnull(OBJECT_SCHEMA_NAME(k.parent_object_id) + '.', '') + OBJECT_NAME(k.parent_object_id)
, k.name, k.is_not_trusted
FROM sys.check_constraints k
WHERE k.parent_object_id = object_id('dbo.testCheck')
ORDER BY 1;
GO
脚本输出:
答案 0 :(得分:2)
检查约束与WHERE子句的不同之处在于,如果表达式求值为空标记,则CHECK允许修改。澄清:WHERE子句过滤掉表达式求值为 false 或空标记的行;检查约束仅筛选出评估为 false 的修改。
您编写的表达式始终求值为null,因为它在其中与null进行比较。将= null
更改为is null
。
另外,Check约束的不同用法对CHECK / NOCHECK有不同的默认值,所以你应该养成总是指定它的习惯。
请尝试以下操作。
ALTER TABLE dbo.testCheck WITH CHECK
WITH CHECK
ADD CONSTRAINT ck_testCheck
CHECK (checkMe IS null or checkMe = '1' or checkMe = '2');
编辑:重新"但我想知道为什么这个示例评估为True",正如您已经解决的那样,您的示例评估不是 true 但是检查约束允许的空标记。对不起,我应该更好地解释一下。
答案 1 :(得分:0)
按照指定here:
CHECK约束拒绝评估为FALSE的值。
换句话说:
如果检查的条件对于表中的任何行不是FALSE,则CHECK约束返回TRUE。
在您的情况下,表达式(checkMe is null or checkMe = '1' or checkMe = '2')
的计算结果为NULL(又名未知),并且CHECK约束返回TRUE(因为它检查的条件不是FALSE)
来自同一来源的一个很好的例子:
例如,假设您在int列MyColumn上放置一个约束 指定MyColumn只能包含值10(MyColumn = 10)。如果将值NULL插入MyColumn,数据库引擎 插入NULL并且不会返回错误。