2008-11-14 175 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));