动态SQL,一次比较两列记录

时间:2013-06-04 17:46:56

标签: oracle dynamic plsql record rowtype

场景:我们在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上添加了begin / end。当我尝试运行那个版本时,它给了我一个错误,因为它不知道旧/新记录。当我在不执行执行的情况下运行,但只是转储生成的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:

但当然诀窍是目标变量必须处理一堆不同类型的列 - char,date等。所以需要变换old / newvalue变量,以及处理它的逻辑,它变得不那么有趣了。

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

1 个答案:

答案 0 :(得分:0)

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