The correlation names and pseudorecords the represent, i.e. :old
and :new
by default, only have any meaning for row-level triggers:
Note:
This topic applies only to triggers that fire at row level—that is, row-level simple DML triggers and compound DML triggers with row-level timing point sections.
You cannot refer to these in a statement-level trigger, and only :old
would have any meaning in a delete
trigger. On the other hand, statement-level triggers fire even if no data is affected, whereas a row-level trigger won't fire if, in your example, no data is deleted - because there are no matching rows in your table. (This applies for instead of
triggers for views as well, in case you're wondering if that would be a workaround).
So basically you can't do what you're attempting - conditionally deciding whether to delete from another table instead - from a trigger. Triggers are rarely the right answer. For your 'scenario where if it doesn't exist on my table i should try to find it on other site and delete it' you can try to delete a row locally, test whether it did anything, and then decide to delete from the remote table if it didn't. In a PL/SQL block that might be as simple as:
create procedure delete_client(p_name clients.name%type) as
begin
delete from clients where name = p_name;
if sql%rowcount = 0 then
delete from clients@site2 where name = p_name;
end if;
end delete_client;
/
And rather than deleting directly from the table, you make everyone call the procedure instead. Say you start off with some data:
select * from clients;
ID NAME
---------- ----------
1 Joe
2 Anna
select * from clients@site2;
ID NAME
---------- ----------
1 Joe
3 Max
Then calling the procedure for two names:
exec delete_client('Joe');
exec delete_client('Max');
... has removed local and remote records appropriately:
select * from clients;
ID NAME
---------- ----------
2 Anna
select * from clients@site2;
ID NAME
---------- ----------
1 Joe
Joe
was only deleted from the local schema despite existing in both; Max
didn't exist locally so was deleted from the remote schema.
It doesn't have to be a procedure; if you're deleting through JDBC etc. you can test the result of an execute()
call to see how many rows were affected, which is all sql%rowcount
is doing really, and the application code can decide whether to do the second delete
.
But with a procedure (probably in a package) you can grant execute
on that, and remove delete
privileges from the users, so they can't bypass this check and do a straight delete from clients where ...
If you really want some 'display' output for testing purposes:
create procedure delete_client(p_name clients.name%type) as
begin
delete from clients where name = p_name;
if sql%rowcount > 0 then
dbms_output.put_line('Deleted ' || sql%rowcount
|| ' rows from local schema for "' || p_name || '"');
else
delete from clients@site2 where name = p_name;
if sql%rowcount > 0 then
dbms_output.put_line('Deleted ' || sql%rowcount
|| ' rows from remote schema for "' || p_name || '"');
else
dbms_output.put_line('No rows deleted on local or remote schema for "'
|| p_name || '"');
end if;
end if;
end delete_client;
/
set serveroutput on
exec delete_client('Joe');
anonymous block completed
Deleted 1 rows from local schema for "Joe"
exec delete_client('Max');
anonymous block completed
Deleted 1 rows from remote schema for "Max"
exec delete_client('Fred');
anonymous block completed
No rows deleted on local or remote schema for "Fred"
But you shouldn't assume anyone calling your procedure will have serveroutput
on, or even be using a client capable of consuming dbms_output
messages.