表检查约束允许无效数据

时间:2014-04-10 20:53:39

标签: sql sql-server sql-server-2008-r2 check-constraints check-constraint

当我使用下面的测试脚本创建检查约束时,仍然允许违反约束的数据进入表中,并且约束仍显示为受信任。

我意识到检查约束没有正确检查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

脚本输出:

output screenshot

2 个答案:

答案 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并且不会返回错误。