Question

I want to make a trigger that will be executed for each row before delete on the table Clients, what I'm trying to do is when some one tries to delete a row :

DELETE FROM Clients WHERE id=5 AND name = 'test';

I want to print something on the screen like : "you deleted with the following conditions : id is 5 , name is test " or execute another query with same conditions ...

Any kind of help is very appreciated

EDIT

let's suppose the user typed the following query : DELETE FROM Clients where name = 'test'

create or replace 
TRIGGER DELETECLIENT 
BEFORE DELETE ON CLIENTS
DECLARE 
pragma autonomous_transaction;
name1 clients.name%Type; 
BEGIN
  select name into name1 from clients where  name = %I want here the name in the user query %;   
  IF name1 != null THEN 
    DELETE FROM clients WHERE name = name1;
    commit;
  END IF; 
END; 

what I've tested :

i tried adding :old.name , and :new.name , but this doesn't work when the the row doesn't exist in my database

PS : i'm doing this for educational purpose only, I know the script doesn't make sense. i just wan't to know how to achieve the following task : getting the parameters typed after WHERE in the query

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top