如何使用触发器将基础 table 的所有更新列添加到多行审计 table?

how to use trigger in a way to have all updated columns of base table to multiple rows of audit table?

我正在尝试将 'Base' table 的旧值和新值插入审计 table 'Audit'。 问题在于如何将数据存储在 Audit table 中。 如果更新了不止一列,我应该能够以这种格式存储它。

'Audit'table

的结构
Id | Column_Name | Old_Value | New_Value
 1 | Strike      | 4         | 5
 2 | Spare       | 3         | 7
 3 | Score       | 10        | 18

我的解决方案给出了以下结构

Id | old_strike | new_strike | old_spare | new_spare | old_score | new_score
1  | 4          | 5          | 3         | 7         | 10        | 18

我试过使用触发器将旧值和新值保存在一行中,但很难弄清楚如何遍历每列的单个插入语句。

AFTER INSERT OR UPDATE OR DELETE ON frame  -- after event
FOR EACH ROW    // fires for each record
BEGIN

INSERT INTO frame_audit(bowler_id,game_id,frame_number,
old_strike,new_strike,
old_spare,new_spare,
old_score,new_score,
change_date,operation)

VALUES(:NEW.bowler_id,:NEW.game_id,:NEW.frame_number,
:OLD.strike,:NEW.strike,
:OLD.spare,:NEW.spare,
:OLD.score,:NEW.score,
SYSDATE,'UPDATE');
END audit_frames```

// Structure of 'Audit' table
Id | Column_Name | Old_Value | New_Value
 1 | Strike      | 4         | 5
 2 | Spare       | 3         | 7
 3 | Score       | 10        | 18

如评论所述,没有选项可以动态获取特定于每个列名称的 OLDNEW 值。您所能做的就是为所有具有硬编码列名的列编写显式插入。

 ...
 ...

BEGIN


INSERT INTO frame_audit (Id ,Column_Name , Old_Value , New_Value)
SELECT  audit_seq.nextval,'bowler_id',old.bowler_id,new.bowler_id 
FROM DUAL WHERE 
 (    old.bowler_id <> new.bowler_id OR
      (old.bowler_id is NULL     and new.bowler_id is NOT NULL) OR
      (old.bowler_id is NOT NULL and new.bowler_id is NULL   ) 
 );

INSERT INTO frame_audit (Id ,Column_Name , Old_Value , New_Value)
SELECT  audit_seq.nextval,'game_id',old.game_id,new.game_id 
FROM DUAL WHERE 
 (    old.game_id <> new.game_id OR
      (old.game_id is NULL     and new.game_id is NOT NULL) OR
      (old.game_id is NOT NULL and new.game_id is NULL   ) 
 );

--similar inserts for all other columns


 ...

END;

这里我假设您创建了一个序列来为审计生成 ID table。

您可以使用 NVLCOALESCE 简化冗长的 NULL 检查表达式,但您应该根据每列的数据类型使用它。如果列定义为 not null,一个简单的 <> 检查就足够了。对于 DATE/TIMESTAMP 相关列,如果您想以所需格式存储它,则需要使用 TO_CHAR