Oracle触发器根据更新列的数据更新表的所有行

时间:2015-09-09 07:56:02

标签: oracle triggers

我的要求是更新表中input_disp_req ='Y'的所有行的序列号,更新列 input_disp_req 时请帮我创建触发器。即使我在更新后使用过,我也会收到错误。

ORA-04091(表fce_template正在变异。触发器/函数可能看不到它)

CREATE OR REPLACE TRIGGER fce_trigger
   AFTER UPDATE of input_disp_req ON fce_template
  for each row
BEGIN
      update fce_template
         set pos_clmn = fce_seq.nextval
       where region = :new.region
         and mode_name = :new.mode_name
         and input_disp_req = 'Y';
END;

如果有其他方法可以告诉我。请帮我。非常感谢提前:)

有3列input_disp_req,pos_clmn和pos_seq ...

  • 列input_disp_req包含值为Y或N(种类为 有效/无效指示器)
    • 列pos_seq维护序列号,与input_disp_req列中的Y或N无关
    • 列pos_clmn基于input_disp_req = Y
    • 的值维护序列号

所以我的要求是,当我将列input_disp_req中的值更新为N / Y触发器时应该 更新pos_seq排序的所有匹配行的列pos_clmn的序列值。

input_disp_req = Y表示根据我的要求,输入数据中存在该值。

3 个答案:

答案 0 :(得分:2)

您可以尝试以下列方式使用复合触发器: 每行之后: 获取更新行的rowid或key列并将其放入pl / sql集合

声明后: 遍历所有行并更新序列

它应该摆脱“变异表”错误...

类似的东西(它可能缺少一些var声明):

    create or replace trigger your_trigger
   for update on your_table
   compound trigger

   --Trigger level variables so we capture all updates.
   type t_rec is record(
      flg varchar2(1));
   type t_list_tab is table of t_rec index by pls_integer;
   l_tab t_list_tab;

after each row is

            l_new_the_id := :new.the_id;
            l_old_the_id := :old.the_id;

            if (not l_tab.exists(l_new_the_id)) then
               l_cnt_tab(l_new_the_id).flg := '';
            end if;


end after each row;

after statement is

      if (l_tab.count != 0) then

         for l_idx in l_tab.first .. l_tab.last loop
               --your updates here
          end loop;
      end if;

end after statement;

end;

可能你只需要使用触发器,但每个人都只会告诉你你不应该 - 当你试图跟踪变化或发现错误时触发器会很痛苦 - 可能更好的方法是使用一个程序来更新表格,并使用其逻辑做所有的事情......

答案 1 :(得分:2)

让我们看看我是否能理解你的要求以及你迄今所做的评论......

似乎已经有一个列代表您的订单(您对DavidAldridge的评论)。我们假设它被称为order_col。这样就可以按顺序检索记录:

select *
from fce_template
order by order_col;

您还可以获得“' Y'按顺序记录:

select *
from fce_template
where input_disp_req = 'Y'
order by order_col;

还有某个地区和模式:

select *
from fce_template
where region = :region
and mode_name = :mode_name
and input_disp_req = 'Y'
order by order_col;

但不知何故,这似乎还不够。您是否只想应用行号(在区域和模式内)?可以使用ROW_NUMBER:

完成
select f.*, row_number() over (order by order_col) as pos_clmn
from fce_template f
where region = :region
and mode_name = :mode_name
and input_disp_req = 'Y'
order by order_col;

对于所有数据:

select 
  f.*, 
  row_number() over (partition by input_disp_req, region, mode_name
                     order by order_col) as pos_clmn
from fce_template f
where input_disp_req = 'Y'
order by order_col;

如果这是您想要的,您可以随时创建行号。你不必存储它们。存储它们甚至会很糟糕,因为你会引入冗余:订单将被提供两次,一次是order_col,一次是pos_clmn。别这么做。

答案 2 :(得分:1)

这不是答案。我只想说明你在做什么。

说你有这张桌子:

input_disp_req  region  mode_name  pos_clmn  some_data
Y               R1      M1         1         A
Y               R1      M1         2         B
Y               R1      M1         3         C
N               R1      M1         4         D
N               R1      M1         5         E

现在让我们来看看这个更新声明:

update fce_template set input_disp_req = 'Y' where input_disp_req = 'N';

这会更新两条记录,因此触发器会被触发两次。首次执行时,将有四条记录给序列号6到9。在第二次执行时,所有五个记录将为“Y”并获得序列号10到14.因此,在您更新后,您的记录可能如下所示:

input_disp_req  region  mode_name  pos_clmn  some_data
Y               R1      M1         14        A
Y               R1      M1         10        B
Y               R1      M1         12        C
Y               R1      M1         13        D
Y               R1      M1         11        E

你从中获得了什么?它似乎没有意义。您似乎正在使用错误的approch来实现您想要实现的目标。