【问题标题】:Update table column on update related table column in pl sql在pl sql中更新相关表列上更新表列
【发布时间】:2015-03-31 19:37:27
【问题描述】:

我有一个数据库,其中包含这两个表:

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

当我在 SIFRADOB 是主键的 DOBAVLJAC 上更改列“naziv”时,我需要一个语句触发器来更新表 NARUDZBENICA 中所有行中的列“naziv”,其中 SIFRADOB 以“0”开头。

这是我想出的:

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;

【问题讨论】:

  • alter 语句是 DDL 并隐式提交;而且您不能在触发器中提交。在这种情况下,您可能可以在您禁用的触发器中放置一些逻辑来阻止它触发。还有其他几个问题。但不确定我是否真的遵循你在做什么。

标签: oracle plsql oracle11g triggers oracle-sqldeveloper


【解决方案1】:

我不知道您在尝试做什么来禁用和启用另一个触发器。否则我几乎可以看到你想要做什么,我只是不明白为什么。

简而言之:当表 DOBAVLJAC 中的字段 NAZIV 更新时,该字段的旧值将保存到表 NARUDZBENICA 中的同一字段中,其中字段 SIFRADOB 以字符“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;

我刚刚想到为什么您可能会禁用另一个触发器。它是另一个表上的更新触发器,它监视相同的字段,进而将更改传播到 DOBAVLJAC。这将创建一个无限循环的更新。 (这也意味着您可能应该使用 :new.NAZIV 值而不是 :old.NAZIV。)

有几个技巧可以解决这个问题。更多涉及的是重命名两个表并使用原始表名创建视图。每个视图上的“替代”触发器都会更新两个表的 NAZIV 更改。没有循环。

这是一个相当复杂的解决方案。一个更简单的方法(涉及较少的对象更改)是在两个表中创建一个标志列。此列的值始终为 NULL。当触发器执行时(它必须是before 触发器),它会检查标志列的新值。如果它仍然为空,则意味着这是第一个更新,因此将更新发送到另一个表。 更新将 NAZIV 值设置为新值并且将标志字段设置为任何非空值。非空值告诉另一个触发器这是一个传播更新,因此结束传播。它将 :new.flag 值更改为 null (您实际上从未更改表中标志字段的内容)并且只允许更新。这个逻辑在两个表的触发器中是相同的。

Oracle 12c 和不可见的列使这变得更容易一些。它只是允许您从正常视图中隐藏标志字段,这样人们就不会总是过来询问它的用途。

在阅读我的描述时,我认为我的观点并不清楚,尤其是对于非英语母语人士。所以这里是触发代码:

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;

这不是产品级编码,但我希望它能说明这个想法。

【讨论】:

    【解决方案2】:

    :new:old 标识符只能在row-level 触发器中使用。对于statement level 触发器,禁止使用:new:old 标识符。 你也不能在触发器中commit。因此,如果您想做任何 DML 操作,您需要使用 autonomous 事务。请看下面如何做到这一点。

    此触发器将在表A_TABLEID 的列值发生任何变化时触发。 新值将被捕获并传递给匿名交易。

    CREATE OR REPLACE TRIGGER STATEMENT_DOB 
    AFTER UPDATE OF ID ON A_TABLE 
    for each row
    BEGIN
    
     proc_upd_tb(:new.id); 
    
    END;
    

    自治事务:

    数据可以在这里更新和提交,如图所示。

    create or replace procedure proc_upd_tb(id number)
    as 
    PRAGMA AUTONOMOUS_TRANSACTION;
    begin
    
       UPDATE AA
        SET A = id;
        where <condition> ;
        commit;
    
    end;
    

    【讨论】:

      猜你喜欢
      • 2015-10-01
      • 2015-08-07
      • 1970-01-01
      • 2017-12-18
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多