场景:我们在 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:
但当然诀窍是目标变量必须处理一堆不同类型的列——字符、日期等。所以需要有旧/新值变量的变体,以及处理它的逻辑,它变得不那么有趣了。
有什么更优雅的方式来做到这一点的建议吗?我已经检查了该站点,并没有很想找到任何看起来像我正在尝试做的事情。