【问题标题】:Efficient way to get updated column names on an after update trigger在更新后触发器上获取更新列名的有效方法
【发布时间】:2017-11-03 15:01:41
【问题描述】:

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

但问题是如果有更多的列(至少 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$transaction 或类似的东西)?

【问题讨论】:

  • 你可以做一个before更新触发器,并可以将:new.col与':old.col'进行比较,但首先,拥有100个以上的列听起来有点多。
  • 似乎标准化是邪恶的
  • ERP 系统中,似乎每个表至少有 40 列。我猜这可能不是因为规范化,或者 ERP 系统无法对用户自定义表进行非规范化......只是一个想法......

标签: oracle plsql cursor database-trigger


【解决方案1】:

不是通过UPDATING() 获取UPDATED 列的最佳方式

你可以像这样使用隐式游标来改变你的代码,它会快一点

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;
/

【讨论】:

  • 我的预感是......如果 oracle 为 UPDATING('colname') 返回 true,那么它必须在 db 事务 v$ 表中的某处具有更新列的列表(可能是隐藏的)......所以如果我们直接获取,如果更新是在单个列上完成的,我们不需要遍历所有列(100 列)
  • 你有什么想法尝试更新动态 sql 表达式,那一刻你知道你正在更新哪些列,你可以收集列名,值然后通过动态 sql 构建插入语句,那一刻你知道哪些列正在更新?
  • 这只是对特定表设置一个简单的审核...仅此而已...这是为了提醒用户,她对表做了哪些更改
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 2015-11-18
    • 2013-05-25
    • 2016-11-03
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 1970-01-01
    相关资源
    最近更新 更多