Oracle PL/SQL触发器:在update语句后自动重置列值

Oracle PL/SQL触发器:在update语句后自动重置列值,sql,oracle,plsql,triggers,oracle12c,Sql,Oracle,Plsql,Triggers,Oracle12c,出于测试目的,我希望将以下场景自动化: 将我的表的列状态设置为已关闭的值(使用update语句) 提交更新,以便其他用户可以看到状态的新值 等待1分钟 将我的表格的列状态重置为其原始值init(使用触发器) 提交更新,以便其他用户可以看到状态的原始值 我试过用这个扳机,但不起作用 ORA-04091:表名正在变化,触发器/函数可能看不到它 既然不允许在触发器内提交,那么还有其他方法可以解决这个问题吗?使用基于事件的作业?这似乎是个坏主意睡眠()触发器内部?这只会增加锁并占用资源 相反,您可以使用

出于测试目的,我希望将以下场景自动化:

  • 将我的表的列状态设置为已关闭的值(使用update语句)

  • 提交更新,以便其他用户可以看到状态的新值

  • 等待1分钟

  • 将我的表格的列状态重置为其原始值init(使用触发器)

  • 提交更新,以便其他用户可以看到状态的原始值

  • 我试过用这个扳机,但不起作用

    ORA-04091:表名正在变化,触发器/函数可能看不到它


    既然不允许在触发器内提交,那么还有其他方法可以解决这个问题吗?使用基于事件的作业?

    这似乎是个坏主意<代码>睡眠()触发器内部?这只会增加锁并占用资源

    相反,您可以使用视图或虚拟列。将
    closeDate
    存储为表中的一列(如果愿意,可以使用触发器进行设置)


    要将其作为作业运行,您需要一个可以调用的过程。我假定您希望对特定记录执行此操作,而不是对整个表执行此操作,因此使用ID参数

    create or replace procedure reset_my_table_status
        ( p_id in number )
    is
    begin 
        update my_table
        set status = 'INIT'
        where id = p_id;
        commit;
    end;
    /
    
    然后,从触发器提交作业,在60秒后调用该过程:

    CREATE OR REPLACE TRIGGER RESET_COLUMN
    AFTER UPDATE OF STATUS ON MY_TABLE
    FOR EACH ROW
    WHEN (NEW.STATUS != 'INIT')
    DECLARE
        jn number;
        pragma autonomous_transaction;
    BEGIN
        dbms_job.submit(jn 
                       , what=>'reset_my_table_status('||:new.id||');'
                       , next_date => sysdate + 60/86400
          );
        commit;
    END;
    /
    
    设置
    next\u date
    参数意味着作业将在60秒内触发,因此无需调用
    sleep()。请记住,要运行作业,需要作业队列进程init参数的值大于0。我们必须承诺提交一份工作;所以我们需要一个自治事务,因为通常我们不能从触发器发出提交

    或者,您可以只构建一个过程(甚至是一个匿名块)


    然后,只需对要测试的ID运行该过程

    :new.status:='INIT'
    并从触发器中删除
    commit
    。触发器中不能有任何事务处理,但我需要提交这些事务,以便其他用户可以使用它们。请查看已编辑的问题摘要,但在我的情况下,修改表格结构不是一个选项。@nogc。视图不是对表结构的修改(虚拟列是,但不是视图)。非常感谢。它按预期工作,但我需要在
    what=>'reset_my_table_status(“| |:new.id | |”)中添加一个分号否则我会得到Oracle-PLS-00103。请看OOPS。很抱歉。
    
    create or replace procedure reset_my_table_status
        ( p_id in number )
    is
    begin 
        update my_table
        set status = 'INIT'
        where id = p_id;
        commit;
    end;
    /
    
    CREATE OR REPLACE TRIGGER RESET_COLUMN
    AFTER UPDATE OF STATUS ON MY_TABLE
    FOR EACH ROW
    WHEN (NEW.STATUS != 'INIT')
    DECLARE
        jn number;
        pragma autonomous_transaction;
    BEGIN
        dbms_job.submit(jn 
                       , what=>'reset_my_table_status('||:new.id||');'
                       , next_date => sysdate + 60/86400
          );
        commit;
    END;
    /
    
    create or replace procedure my_table_status_test
        ( p_id in number )
    is
    begin 
        update my_table
        set status = 'MEH'
        where id = p_id;
        commit;
    
        DBMS_LOCK.SLEEP(60);  
    
        update my_table
        set status = 'INIT'
        where id = p_id;
        commit;
    end;
    /