我一直在努力解决这个检查约束几个小时,并希望有人能够解释为什么这个检查约束没有做我认为它应该做的事情.
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_DISABLED
并DISABILITY_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);
谢谢你的帮助,迈克尔
虽然我没有Oracle,但我使用PostgreSQL和你的第一个例子(IS_DISABLED
存在NULL
并且DISABILITY_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)
在这里我们清楚地看到,在这种情况下,您的表达式(至少在PostgreSQL上)返回NULL.从手册,
[...]评估为TRUE或UNKNOWN的表达式成功.如果插入或更新操作的任何行产生FALSE结果,则会引发错误异常,并且插入或更新不会更改数据库.[...]
因此,如果Oracle的行为与PostgreSQL相同,则检查约束将通过.
要查看是否是这种情况,请通过明确检查它并查看它是否有效来避免NULL shenanigans:
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));