Как создать триггер Oracle, который удаляет / обновляет только некоторые строки из исходного запроса? - PullRequest
1 голос
/ 04 мая 2020

У меня есть таблица:

create table projects(pid int,name char(10),active int);
insert into projects values(1,'aa',1);
insert into projects values(2,'bb',0);

, и я хочу создать триггер, который не позволяет удалить активный проект (active = 1). Таким образом, для команды: delete from projects where pid in (1,2) будет удалена только строка с pid = 2, а строка с pid = 1 не будет удалена . И об ошибке не будет сообщено (может быть, только предупреждение?).

На SQL Сервере Я делаю это так:

create trigger nondel on projects instead of DELETE
as
delete from projects where pid in (select pid from deleted where active=0)
end

Так что «вместо» триггера и только строки которые выполняют условие удаления и условие active = 0 удаляются.

В Oracle я пробовал «для каждого» триггера:

create trigger nondel before delete on projects
for each row
when :old.active=1
begin
RAISE_APPLICATION_ERROR (-20502, 'Active rows cannot be deleted!');
end

, но RAISE_APPLICATION_ERROR прерывает всю транзакцию, и ничего не происходит удален. Мой вопрос: возможно ли объявить триггер «для каждой строки» с кодом, который, когда условие выполняется, не удаляет строку, но и не вызывает никакой ошибки, просто продолжает с последующими строками? Или, может быть, лучше использовать триггер оператора?

1 Ответ

0 голосов
/ 04 мая 2020

Это полностью против Oracle архитектуры. Можно нормально блокировать действие, как вы показали с помощью триггера RAISE_EXCEPTION, но совершенно необычно подавлять действие без сообщения об ошибке.

Теоретически это можно реализовать с помощью триггера INSTEAD OF , но они работают только для представлений:

create view forcefield as select * from projects;

create or replace trigger tiud_forcefield
  instead of insert or update or delete on forcefield
  for each row
begin
  if INSERTING then
    INSERT INTO projects(pid, name, active) VALUES (:new.pid, :new.name, :new.active);
  end if;

  if UPDATING then
    UPDATE projects SET pid=:new.pid, name=:new.name, active=:new.active
     WHERE pid = :old.pid;
  end if;

  if DELETING then
    if :old.active = 0 then
      DELETE FROM projects WHERE pid = :old.pid;
    end if;
  end if;
end;
/

В защищенном представлении есть все строки таблицы:

select * from forcefield;
PID NAME ACTIVE
1   aa   1
2   bb   0

Если вы удалите неактивный проект, он будет работать нормально:

delete from forcefield where pid=2;
1 row deleted.

select * from forcefield;
PID NAME ACTIVE
1   aa   1

Однако, если вы пытаетесь удалить активный проект, он все равно утверждает, что удалил одну строку, но не сделал этого. Yikes!

delete from forcefield where pid=1;
1 row deleted.

select * from forcefield;
PID NAME ACTIVE
1   aa   1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...