0

场景:我们在 Oracle 数据库中的某些表上设置了闪回。时不时地,我们想看看哪些字段从一行更改为另一行。我们当然可以目视检查,但这很容易出错。

所以我有了一个“绝妙”的想法,尝试逐行遍历,将当前记录存储到一个记录变量中,并将先前的记录存储到另一个记录变量中。然后,逐个字段,比较每个字段,如果不同,打印出字段名称和值。像这样的东西:

DECLARE CURSOR myflash IS SELECT * FROM myflashtable;
OLDRECORD myflashtable%ROWTYPE;
NEWRECORD myflashtable%ROWTYPE;
dynamic_statement varchar2(4000);
cursor colnames is select * from all_tab_columns where table_name = 'myflashtable';
begin
if not myflash%ISOPEN then
  open myflash;
end if;
fetch myflash into NEWRECORD;
while myflash%FOUND loop;
  for columnnames in colnames loop
      /* cobble together dynamic SQL along the lines of
         "if oldrecord.column_name != newrecord.column_name 
         then print some information``....end if;"
      */
         execute immediate dynamic_statement;
  end loop;
  OLDRECORD := NEWRECORD;
  fetch myflash into NEWRECORD;
end loop;
end;

这自然是行不通的。最初它给了我“无效的 SQL 语句”,我在动态 SQL 中添加了开始/结束。当我尝试运行版本时,它给了我一个错误,因为它不知道旧/新记录。当我在不执行执行的情况下运行,而只是转储生成的 SQL 时,它会逐步遍历每条记录上的所有列,因此部分逻辑正在运行。

我很确定有更好的方法来做到这一点,或者让它发挥作用。一种想法是做一些事情,比如声明旧/新值变量,然后使用动态 SQL 将旧/新记录字段移动到其中的每一个:

EXECUTE IMMEDIATE 'oldvalue := OLDRECORD.'||columnnames.column_name;
EXECUTE IMMEDIATE 'newvalue := NEWRECORD.'||columnnames.column_name;
IF oldvalue != newvalue then
   /* print some stuff */
END IF:

但当然诀窍是目标变量必须处理一堆不同类型的列——字符、日期等。所以需要有旧/新值变量的变体,以及处理它的逻辑,它变得不那么有趣了。

有什么更优雅的方式来做到这一点的建议吗?我已经检查了该站点,并没有很想找到任何看起来像我正在尝试做的事情。

4

1 回答 1

0

你在正确的轨道上。但这是相当多的编程工作要做。读取连接中的旧表和新表,将其与正确的主键链接并循环遍历它。您可以使用DMBS_SQL包来构建动态游标并遍历表。

于 2013-06-04T19:25:00.120 回答