Ограничение проверки Oracle - PullRequest
3 голосов
/ 15 ноября 2008

Я боролся с этим проверочным ограничением в течение нескольких часов и надеялся, что кто-то будет достаточно любезен, чтобы объяснить, почему это проверочное ограничение не делает то, что, я думаю, должно быть.

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

Спасибо за вашу помощь, Michael

Ответы [ 4 ]

5 голосов
/ 15 ноября 2008

Хотя у меня нет 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. С инструкция ,

[...] Успешные выражения, имеющие значение ИСТИНА или НЕИЗВЕСТНО. Если какая-либо строка операции вставки или обновления выдает результат FALSE, возникает исключение ошибки, и вставка или обновление не изменяют базу данных. [...]

Итак, если Oracle ведет себя так же, как PostgreSQL, проверочное ограничение будет pass .

Чтобы увидеть, так ли это, избегайте махинаций 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));
1 голос
/ 15 ноября 2008

Я не уверен, почему проверка соединения не работает, но это работает:

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

1 голос
/ 15 ноября 2008

Попробуйте использовать NVL в состоянии проверки.

0 голосов
/ 15 ноября 2008

Это решение работает.

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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...