【问题标题】:Oracle trigger to update all the rows of table based on the data of updating columnOracle触发器根据更新列的数据更新表的所有行
【发布时间】:2015-09-09 17:48:09
【问题描述】:

我的要求是更新表中 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(种类 活动/非活动指标)
    • 无论 input_disp_req 列中的 Y 还是 N,pos_seq 列都保持序列号
    • 列 pos_clmn 根据 input_disp_req = Y 的值维护序列号

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

input_disp_req=Y 表示传入数据中存在符合我要求的值。

【问题讨论】:

  • 这是一个奇怪的要求。为什么仅仅因为一条记录得到更新,你就想用新数字更新表中的几条记录?这看起来很可疑,可能表明您的数据库设计或数据访问概念存在缺陷。
  • 因为我想为 input_disp_req ='Y' 的所有记录维护正确的序列号。因为那个序列没有被用于其他目的。
  • 什么是“正确的顺序”?没有顺序。一个随机的“Y”记录获得#1,另一个随机选择的“Y”记录获得#2,依此类推。我认为这没有任何意义。
  • @DavidAldridge 还有一列根据我要修改 pos_clmn 列的列的顺序维护不可编辑的序列。例如... pos_seq 对于 input_disp_req = Y 或 N 的序列将不相同,但 pos_clmn 将仅基于 Y 具有序列,以便我保持初始顺序

标签: oracle triggers


【解决方案1】:

让我们看看我是否能理解您的要求以及您到目前为止所做的 cmets...

似乎已经有一个列代表您的订单(您对 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 给出。不要那样做。

【讨论】:

  • 好的。阅读您调整后的问题,这个答案似乎完美匹配。不是吗?
  • 感谢您的宝贵时间和帮助...这真的很有帮助。我刚刚修改了我的查询并使用了 rownum 并且它有效。现在我不需要创建触发器来维护序列
【解决方案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;

您可能只需要使用触发器,但每个人都会告诉您不应该 - 当您尝试跟踪更改或发现错误时,触发器会让人头疼 - 可能更好的是使用程序来更新表格并使用其逻辑做所有事情......

【讨论】:

  • 你能给我一个同样的例子吗
  • 我刚刚编辑了我的答案;)你总是可以去获取有关复合触发器的 oracle 文档以阅读更多信息 - 这真的很棒!
  • 我认为这几乎值得赞成,因为它找到了一种巧妙的破解方法来解决可能非常糟糕的设计。
【解决方案3】:

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

假设你有这张桌子:

input_disp_req 区域 mode_name pos_clmn some_data 是 R1 M1 1 一个 是 R1 M1 2 B 是 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。在第二次执行时,所有 5 条记录都将是“Y”并获得 10 到 14 的序列号。因此,在您更新后,您的记录可能如下所示:

input_disp_req 区域 mode_name pos_clmn some_data 是 R1 M1 14 A 是 R1 M1 10 B 是 R1 M1 12 C 是 R1 M1 13 D 是 R1 M1 11 E

你从中获得了什么?这似乎没有意义。您似乎对想要实现的目标使用了错误的方法。

【讨论】:

  • 是的,你是对的,它不会第二次增加序列.. 但为此我想在最后一次触发调用后重置序列号 0。所以它始终以 0 开头。
  • 你能推荐一个更好的方法
  • 是的,可能。但为了什么?你想达到什么目标?您以随机顺序给出数字(在我的示例中为数字 10 到 14,但与数字 1 到 5 相同)。这应该有什么用?
  • 还有一列维护了根据我要修改 pos_clmn 列的列的顺序不可编辑的序列。例如 ... pos_seq 的序列对于 input_disp_req = Y 或 N 都不同,但 pos_clmn 的序列仅基于 Y
  • 我不明白你在给我看什么。用一句话告诉我你想达到什么。 pos_clmn 似乎表明了记录的顺序,但是您的触发器会破坏该顺序并通过随机为记录提供新数字来应用另一个顺序。所以 pos_clmn 并不意味着对记录进行排序。但它还代表什么?
【解决方案4】:

您可以尝试在更新前触发:

CREATE OR REPLACE TRIGGER fce_trigger
   BEFORE UPDATE of input_disp_req ON fce_template

【讨论】:

    猜你喜欢
    • 2014-06-16
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 2021-09-17
    • 2012-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多