Таким образом, правило, которое вы хотите применить, заключается в том, что TABLE_1 может ссылаться только на TABLE_2, если какой-либо столбец в TABLE_2 равен нулю или меньше.Хммм .... Давайте разберем логику триггера, а затем обсудим правило.
Триггер должен выглядеть следующим образом:
CREATE or replace TRIGGER "New_Trigger"
AFTER INSERT OR UPDATE ON "Table_1"
FOR EACH ROW
declare
n "Table_2"."number".type%;
BEGIN
Select "Table_2"."number"
into n
from "Table_2"
WHERE "Table_2"."ID" = :new.FK_Table_2_ID;
if n > 0
THEN RAISE_APPLICATION_ERROR(-20000, 'this is not allowed');
end if;
END;
Обратите внимание, что ваше сообщение об ошибке должно содержать некоторыеполезная информация, такая как значение первичного ключа TABLE_1, когда вы вставляете или обновляете несколько строк в таблице.
Здесь вы пытаетесь применить тип ограничения, известный какУТВЕРЖДЕНИЕ.Утверждения указаны в стандарте ANSI, но Oracle их не реализовал.Ни одна другая СУБД не подходит к этому.
Утверждения проблематичны, потому что они симметричны.То есть правило также должно быть применено к TABLE_2.В данный момент вы проверяете правило при создании записи в TABLE_1.Предположим, что через некоторое время пользователь обновит TABLE_2.NUMBER, чтобы он был больше нуля: ваше правило теперь нарушено, но вы не будете знать, что оно нарушено, пока кто-нибудь не выдаст совершенно не связанное ОБНОВЛЕНИЕ в TABLE_1,который тогда потерпит неудачу.Гадость.
Итак, что делать?
Если правило действительно
TABLE_1 может ссылаться только на TABLE_2, если TABLE_2.NUMBER равен нулю
затем вы можете принудительно применить его без триггеров.
- Добавить ограничение UNIQUE для TABLE_2 для (ID, NUMBER);вам нужно дополнительное ограничение, потому что ID остается первичным ключом для TABLE_2.
- Добавьте в TABLE_1 фиктивный столбец с именем TABLE_2_NUMBER.По умолчанию он равен нулю и имеет ограничение проверки, чтобы гарантировать, что он всегда равен нулю.(Если вы используете 11g, вам следует рассмотреть возможность использования виртуального столбца для этого.)
- Измените внешний ключ на TABLE_1, чтобы (FK_Table_2_ID, TABLE_2_NUMBER) ссылался на уникальное ограничение, а не на первичный ключ TABLE_2.
- Сбросьте триггер "New_Trigger";он вам больше не нужен, поскольку внешний ключ не позволит никому обновить TABLE_2.NUMBER до значения, отличного от нуля.
Но если правило действительно так, как я его сформулировал сверху, то есть
TABLE_1 может ссылаться только на TABLE_2, если TABLE_2.NUMBER не больше нуля (т.е. отрицательные значениявсе в порядке)
тогда вам нужен еще один триггер, на этот раз на TABLE_2, чтобы применить его на другой стороне правила.
CREATE or replace TRIGGER "Assertion_Trigger"
BEFORE UPDATE of "number" ON "Table_2"
FOR EACH ROW
declare
x pls_integer;
BEGIN
if :new."number" > 0
then
begin
Select 1
into x
from "Table_1"
WHERE "Table_1"."FK_Table_2_ID" = :new.ID
and rownum = 1;
RAISE_APPLICATION_ERROR(-20001, :new.ID
||' has dependent records in Table_1');
exception
when no_data_found then
null; -- this is what we want
end;
END;
Этот триггер не позволит вам обновить TABLE_2.NUMBER до значения больше нуля, если на него ссылаются записи в TABLE_2.Он срабатывает только в том случае, если инструкция UPDATE касается TABLE_2.NUMBER, чтобы минимизировать влияние на производительность при выполнении поиска.