Создать триггер, который удаляет строки

Итак, у меня есть эта таблица:

CREATE TABLE orders_rows (
  order_id       NUMBER(10)   PRIMARY KEY,
  row_num        DATE  NOT NULL,
  p_id           NUMBER(10)  NOT NULL,
  quantity       NUMBER(10)  NOT NULL,
);

И я хочу создать триггер, который при обновлении меняет количество на 0 (ноль) -> удалить эту строку.

Я попробовал это:

Триггер CHECK_ORDER_ROW:

create or replace
TRIGGER check_order_row
  AFTER INSERT OR UPDATE on orders_rows
  for each row
BEGIN
  if :new.quantity = 0 then
  DELETE_ORDER_ROW(:new.order_id, :new.row_num);
  end if;
END;

DELETE_ORDER_ROW - это процедура:

Процедура DELETE_ORDER_ROW:

create or replace
PROCEDURE delete_order_row (p_order_id NUMBER, p_row_num NUMBER)
IS
BEGIN
  DELETE orders_rows WHERE (order_id = p_order_id and row_num = p_row_num);
  COMMIT;
END;

Но когда я пытаюсь обновить:

update orders_rows set quantity=0 where (order_id=1 and row_num=1);

Я получаю ошибку:

A trigger (or a user defined plsql function that is referenced in
           this statement) attempted to look at (or modify) a table that was
           in the middle of being modified by the statement which fired it.

Любые изменения я могу сделать? Или попробуйте другие варианты сделать это?

Заранее спасибо!

1 ответ

Решение

Вы, вероятно, не можете (или, по крайней мере, не должны).

Триггер уровня строки в таблице обычно не может запрашивать эту же таблицу, не вызывая исключение изменяющейся таблицы. Если бы вы были действительно настроены, вы могли бы создать пакет, создать коллекцию order_id значения в этом пакете, создайте триггер оператора before, который инициализирует коллекцию, создайте триггер на уровне строк, который заполнил коллекцию :new.order_id, а затем триггер оператора после, который перебрал коллекцию и вызвал delete_order_row, Это, однако, много движущихся частей, чтобы иметь дело с. Как правило, для кода приложения, который устанавливает quantity до 0, чтобы удалить строку вместо. Помещение логики в триггер, который удаляет строку, которую только что вставленное (или обновленное) приложение обычно приводит к потокам приложений, за которыми очень трудно следить (отчасти потому, что вы никогда не видите весь поток сразу, вы постоянно хотите видеть какие триггеры побочных эффектов создают) и ошибки, которые очень трудно понять и отладить.

Если вы решили использовать триггер и не хотите использовать решение с тремя триггерами, вы также можете переименовать таблицу, создать представление с именем order_row и создать instead of вызвать вид, который превратился update на вид в update или delete на базовом столе в зависимости от quantity значение. Это добавляет дополнительный уровень косвенности к вашему коду, и все же имеет тенденцию усложнять отслеживание потоков приложений.

Другие вопросы по тегам