Reputation: 127
So I have this table:
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,
);
And I want to create a trigger that when update changes quantity to be 0 (zero) -> delete this row.
I tried this:
CHECK_ORDER_ROW trigger:
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 is the procedure:
DELETE_ORDER_ROW procedure:
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;
But when I try to update:
update orders_rows set quantity=0 where (order_id=1 and row_num=1);
I get error:
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.
Any changes I can do? Or try other options to do that?
Thanks in advance!
Upvotes: 0
Views: 147
Reputation: 231661
You probably can't (or at least you shouldn't).
A row-level trigger on a table cannot generally query that same table without causing a mutating table exception. If you were really determined, you could create a package, create a collection of order_id
values in that package, create a before statement trigger that initializes the collection, create a row-level trigger that populated the collection with the :new.order_id
, and then an after statement trigger that iterated through the collection and called delete_order_row
. That, however, is a lot of moving pieces to deal with. It would generally make much more sense for the application code that is setting the quantity
to 0 to delete the row instead. Putting logic into a trigger that deletes a row that an application just inserted (or updated) generally leads to application flows that are very difficult to follow (in part because you can never see the entire flow at once, you're constantly looking to see what side-effects triggers are creating) and bugs that are very difficult to understand and debug.
If you're determined to use a trigger and you don't want to go with the three-trigger solution, you could also rename the table, create a view named order_row
and create an instead of
trigger on the view that turned an update
on the view into an update
or a delete
on the base table depending on the quantity
value. That's adding an extra layer of indirection to your code, though, and it still tends to make application flows difficult to follow.
Upvotes: 2