3

我已经为这个检查约束苦苦挣扎了几个小时,并希望有人能善意地解释为什么这个检查约束没有做我认为应该做的事情。

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_ID1 和 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);

谢谢你的帮助,迈克尔

4

4 回答 4

5

虽然我没有 Oracle,但我使用 PostgreSQL 和您的第一个示例(IS_DISABLEDbeingNULLDISABILITY_INCOME_TYPE_IDbeing 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 恶作剧:

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));
于 2008-11-15T00:47:06.217 回答
1

尝试在检查条件中使用NVL 。

于 2008-11-14T21:28:57.630 回答
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)

问候 K

于 2008-11-14T22:00:33.823 回答
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));
于 2008-11-15T07:57:52.107 回答