2008-11-14 135 views
3

我一直在为这个检查约束挣扎几个小时,并希望有人会友好地解释为什么这个检查约束没有做我认为应该做的事情。Oracle检查约束

ALTER TABLE CLIENTS 
add CONSTRAINT CHK_DISABILITY_INCOME_TYPE_ID CHECK ((IS_DISABLED IS NULL AND DISABILITY_INCOME_TYPE_ID IS NULL) OR (IS_DISABLED = 0 AND DISABILITY_INCOME_TYPE_ID IS NULL) OR (IS_DISABLED = 1)); 

从本质上讲,您必须被禁用才能收集伤残收入。看来好像这个检查约束(IS_DISABLED IS NULL AND DISABILITY_INCOME_TYPE_ID IS NULL)的第一部分没有被执行(见下文)。

DISABILITY_INCOME_TYPE_ID的可用值是1和2,这是通过外键强制执行的。 IS_DISABLEDDISABILITY_INCOME_TYPE_ID都可以为空。

-- incorrectly succeeds (Why?) 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (null, 1); 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (null, 2); 

-- correctly fails 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (0, 1); 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (0, 2); 

-- correctly succeeds 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (0, null); 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (1, 1); 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (1, 2); 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (1, null); 
INSERT INTO CLIENTS (IS_DISABLED, DISABILITY_INCOME_TYPE_ID) VALUES (null, null); 

感谢您的帮助, 迈克尔

+0

只是验证我看到了与Oracle 10.2.0.4.0相同的行为。 – 2008-11-14 22:41:48

回答

5

虽然我没有甲骨文,我做了一个快速测试在PostgreSQL和你的第一个例子(IS_DISABLEDNULLDISABILITY_INCOME_TYPE_ID为1):

postgres=> select (null is null and 1 is null); 
?column? 
---------- 
f 
(1 registro) 

postgres=> select (null is null and 1 is null) or (null = 0 and 1 is null); 
?column? 
---------- 
f 
(1 registro) 

postgres=> select (null is null and 1 is null) or (null = 0 and 1 is null) or (null = 1); 
?column? 
---------- 

(1 registro) 

在这里,我们清楚地看到,在THI在这种情况下,你的表达式(至少在PostgreSQL上)返回NULL。来自the manual

[...]表达式评估为TRUE或UNKNOWN成功。如果插入或更新操作的任何行产生FALSE结果,则会引发错误异常,并且插入或更新不会更改数据库。 [...]

所以,如果甲骨文的行为一样的PostgreSQL,检查约束会

要查看是否是这样的话,通过它explicily检查避免NULL有心计,看看它的工作原理:

CHECK ((IS_DISABLED IS NULL AND DISABILITY_INCOME_TYPE_ID IS NULL) 
    OR (IS_DISABLED IS NOT NULL AND IS_DISABLED = 0 AND DISABILITY_INCOME_TYPE_ID IS NULL) 
    OR (IS_DISABLED IS NOT NULL AND IS_DISABLED = 1)); 
+0

我不确定你的答案是否正确,但你的解释对我自己解决这个问题非常有帮助。这整个时间我评估null = 1为假,事实上,Oracle和Postgres评估这个表达式为未知。主要区别。 – BacMan 2008-11-15 07:57:06

1

尝试在检验条件使用NVL

1

我不知道为什么该化合物检查不能正常工作,但这个工程:

ALTER TABLE CLIENTS ADD CONSTRAINT CHK_1 CHECK (IS_DISABLED = 0 AND DISABILITY_INCOME_TYPE_ID IS NULL) 

ALTER TABLE CLIENTS ADD CONSTRAINT CHK_2 CHECK (IS_DISABLED IS NULL AND DISABILITY_INCOME_TYPE_ID IS NULL) 

ALTER TABLE CLIENTS ADD CONSTRAINT CHK_3 CHECK (IS_DISABLED = 1) 

问候 ķ

0

此解决方案。

CHECK 
((IS_DISABLED IS NULL AND NVL(DISABILITY_INCOME_TYPE_ID, 0) = 0) 
OR (IS_DISABLED = 0 AND NVL(DISABILITY_INCOME_TYPE_ID, 0) = 0) 
OR (IS_DISABLED IS NOT NULL AND IS_DISABLED = 1));