简体   繁体   中英

Update table column on update related table column in pl sql

I have a database that among the others contains these two tables:

NARUDZBENICA(**SIFANAR**,DATUM,NAZIV,*SIFRADOB,SIFRAKATALOGA,SIFRAZAP,SIFRANACISP*)
DOBAVLJAC(**SIFRADOB**,NAZIV,MAIL,TELEFON,FAKS)

I need a statement trigger to update column 'naziv' in all rows in table NARUDZBENICA where SIFRADOB starts with '0' when I change column 'naziv' on DOBAVLJAC where SIFRADOB is a primary key.

This is what I came up with:

CREATE OR REPLACE TRIGGER "STATEMENT_DOB" 
AFTER UPDATE OF NAZIV ON DOBAVLJAC 
BEGIN
    EXECUTE IMMEDIATE 'ALTER TRIGGER UPDATE_NAR_FRB DISABLE';
    UPDATE NARUDZBENICA
    SET NAZIV = (SELECT :OLD.NAZIV FROM DOBAVLJAC)
    WHERE ROWNUM > 1 AND SIFRADOB = '%0';   
    EXECUTE IMMEDIATE 'ALTER TRIGGER UPDATE_NAR_FRB ENABLE';          
END;

I don't know what you are trying to do disabling and enabling one trigger in another. Otherwise I can see pretty much what you're trying to do, I just don't understand why.

In plain language: when the field NAZIV in table DOBAVLJAC is updated, the old value of the field is saved to the same field in table NARUDZBENICA where the field SIFRADOB begins with the character '0'.

create or replace trigger STATEMENT_DOB
after update of NAZIV on DOBAVLJAC
begin
    update  NARUDZBENICA
        set NAZIV = :old.NAZIV
    where   SIFRADOB like '0%';
end;

It just occurred to me why you may be disabling the other trigger. It is an update trigger on the other table that watches for that same field to, in turn, propagate the change to DOBAVLJAC. This would create an endless loop of updates. (It would also means you probably should be using the :new.NAZIV value rather than :old.NAZIV.)

There are several tricks to solve that problem. The more involved one is to rename both tables and create views with the original table names. The Instead Of trigger on each view updates the NAZIV changes to both tables. No looping.

That is a rather involved solution. A simpler one (involving fewer object changes) is to create a flag column in both tables. The value of this column is always NULL. When the trigger executes (and it will have to be the before trigger), it checks the NEW value of the flag column. If it is still null, that means this is the first Update so sends an update to the other table. That update sets the NAZIV value to the new value and the flag field to any non-null value. The non-null value tells the other trigger that this is a propagation update so ends the propagation. It changes the :new.flag value to null (you never actually change the contents of the flag field in the table) and just allows the update. This logic would be the same in the trigger on both tables.

This is made a little easier with Oracle 12c and invisible columns. It just allows you to hide the flag field from normal view so people aren't always coming around and asking what it is for.

In reading over my description, I don't think I made my point clearly, especially for non-native English speakers. So here is the trigger code:

create or replace trigger STATEMENT_DOB -- UPDATE_NAR_FRB
before update of NAZIV, Flag on DOBAVLJAC -- NARUDZBENICA
begin
    if updating( Flag ) and not updating( NAZIV ) then
        -- Someone playing around updating Flag only. Don't allow.
        :new.FLAG := null;
    elsif :new.FLAG is null then
        -- Original Update. Propagate to other table
        update  NARUDZBENICA -- DOBAVLJAC
            set NAZIV = :new.NAZIV,
                Flag  = 1
        where   SIFRADOB like '0%';
    else
        -- This was propagation from other table. Just allow the update of NAZIV
        -- but first reset the flag...
        :new.FLAG := null;
    end if;
end;

That is not quite production-level coding, but I hope it illustrates the idea.

:new or :old identifiers can only be used in row-level triggers. For statement level trigger use of :new and :old identifiers is forbidden. Also you cannot commit in a trigger. So incase you want to do any DML operation you need to use an autonomous transaction. See below how you can do it.

This trigger will be fired for any change in column value of ID in table A_TABLE . The new value will be captured and passed on to the anonymous transaction.

CREATE OR REPLACE TRIGGER STATEMENT_DOB 
AFTER UPDATE OF ID ON A_TABLE 
for each row
BEGIN

 proc_upd_tb(:new.id); 

END;

Autonomous Transaction:

Data can be updated here and committed as shown.

create or replace procedure proc_upd_tb(id number)
as 
PRAGMA AUTONOMOUS_TRANSACTION;
begin

   UPDATE AA
    SET A = id;
    where <condition> ;
    commit;

end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM