Oracle 在更新后触发器上获取更新列名的有效方法

Oracle 在更新后触发器上获取更新列名的有效方法,oracle,plsql,cursor,database-trigger,Oracle,Plsql,Cursor,Database Trigger,我使用了以下触发器来提取执行表行更新语句时更新的所有列名 但问题是如果有更多的列(至少100列),性能/效率就会受到关注 触发代码示例: set define off; create or replace TRIGGER TEST_TRIGG AFTER UPDATE ON A_AAA FOR EACH ROW DECLARE mytable varchar2(32) := 'A_AAA'; mycolumn varchar2(32); updatedcols varch

我使用了以下触发器来提取执行表行更新语句时更新的所有列名

但问题是如果有更多的列(至少100列),性能/效率就会受到关注

触发代码示例:

set define off;
create or replace TRIGGER TEST_TRIGG
AFTER UPDATE ON A_AAA
FOR EACH ROW
DECLARE
    mytable varchar2(32) := 'A_AAA';
    mycolumn varchar2(32);
    updatedcols varchar2(3000);

    cursor s1 (mytable varchar2) is 
        select column_name from user_tab_columns where table_name = mytable;
begin

        open s1 (mytable);

        loop
            fetch s1 into mycolumn;
            exit when s1%NOTFOUND;

            IF UPDATING( mycolumn ) THEN
                updatedcols := updatedcols || ',' || mycolumn;
            END IF;

        end loop;
        close s1;
        --do a few things with the list of updated columns
    dbms_output.put_line('updated cols ' || updatedcols);
end;
/
有没有其他方法可以得到这份名单


可能是v$表(v$事务或任何类似的)?

否通过
更新()

您可以像这样使用隐式游标更改代码,这样会快一点

set define off;
create or replace TRIGGER TEST_TRIGG
AFTER UPDATE ON A_AAA
FOR EACH ROW
DECLARE
updatedcols varchar2(3000);
begin
for r in (select column_name from user_tab_columns where table_name ='A_AAA')
    loop
       IF UPDATING(r.column_name) THEN
          updatedcols := updatedcols || ',' || r.column_name;
       END IF;
    end loop;
    dbms_output.put_line('updated cols ' || updatedcols);
end;
/

面对类似的任务,我们最终编写了一个pl/sql过程,该过程列出了表中的列并为我们生成完整的触发器主体,其中静态代码引用了
:new.col
:old.col
。这种触发器的执行速度应该更快(尽管我们没有进行比较)

但是,缺点是,当您稍后向表中添加新列时,很容易忘记更新触发器主体。它可能可以通过监控工作或其他方式进行管理,但目前它对我们有效


另外,我开始好奇那个
更新('COL')
功能是做什么的,现在检查了一下。我发现,如果列出现在
update
语句中,即使列的值实际上没有更改(
:old.col
等于
:new:col
),它也会返回true。如果表由Java Hibernate library之类的东西更新,则这可能会生成不需要的历史记录,Java Hibernate library(默认情况下)总是指定它生成的update语句中的所有列。在这种情况下,您可能希望实际比较触发器主体内部的值,并仅在新值与旧值不同的情况下插入历史记录。

您可以在更新触发器之前执行
,并可以将
:new.col
与“:old.col”进行比较,但首先,100 cols+听起来有点太多了。在
ERP
系统中,标准化似乎是有害的,似乎每个表至少有40列。这可能不是因为标准化,或者ERP系统无法对用户自定义的表进行非标准化。。。只是一个想法…我的直觉是。。。如果oracle为
更新('colname')
返回true,那么它必须在db transaction v$表中的某个位置具有更新列的列表(可能是隐藏的)。。。所以如果我们直接得到它,我们不需要遍历所有列(100列),如果更新是在单个列上完成的,那么您如何考虑尝试更新动态sql表达式,当您知道要更新哪些列时,您可以收集列名、值,然后通过动态sql构建insert语句,此时您知道哪些列正在更新?这只是在特定表上设置一个简单的审核。。。没别的了。。。这是为了提醒用户,她在桌子上做了哪些更改