假设使用常规表而不是对象表,则没有很多选择。您的触发器必须是某种形式的
CREATE OR REPLACE TRIGGER trigger_name
AFTER UPDATE ON table_name
FOR EACH ROW
BEGIN
IF( UPDATING( 'COLUMN1' ) )
THEN
INSERT INTO log_table( column_name, column_value )
VALUES( 'COLUMN1', :new.column1 );
END IF;
IF( UPDATING( 'COLUMN2' ) )
THEN
INSERT INTO log_table( column_name, column_value )
VALUES( 'COLUMN2', :new.column2 );
END IF;
<<repeat for all columns>>
END;
你可以取COLUMN1
,COLUMN2
…COLUMN<<n>>
从数据字典字符串(USER_TAB_COLS
),而不是硬编码他们,但你还是要硬编码在列引用:new
伪记录。
您可以通过查询数据字典(USER_TAB_COLS
或ALL_TAB_COLS
最有可能的代码),使用DDL语句构建一个字符串,然后执行EXECUTE IMMEDIATE
来执行DDL语句,从而编写一段上面生成触发器的代码。然后,每当将新列添加到任何表中时,您都必须调用此脚本,以重新创建该列的触发器。编写和调试这种DDL生成代码很繁琐,但在技术上并不是特别困难。但这很少值得,因为有人会不可避免地添加新列而忘记重新运行脚本,或者有人需要修改触发器来做一些额外的工作,而仅手动更新触发器要比修改和测试生成的脚本更容易。触发器。
不过,更笼统地说,我会质疑以这种方式存储数据的智慧。在历史记录表中为修改后的每一行的每一列存储一行,这使得使用历史记录数据非常具有挑战性。如果某人想知道特定行在特定时间点处的状态,则必须将历史记录表自身连接N次,其中N是该时间点表中的列数。这将是非常低效的,很快就会使人们避免尝试使用历史数据,因为他们无法在合理的时间内使用有用的东西而不会扯掉头发。它’ 通常,使用一个具有与活动表相同的列集的历史记录表(添加一些用于跟踪日期等)的历史记录表以及每次更新该行时,在历史记录表中插入一行更为有效。那会消耗更多的空间,但是通常更容易使用。
Oracle有多种审计数据更改的方法-AUDIT
您可以使用DML,可以使用细粒度审计(FGA),可以使用Workspace Manager或可以使用Oracle Total Recall。如果您要寻找比编写自己的触发代码更多的灵活性,那么我强烈建议您研究这些本质上更自动化的其他技术,而不是尝试开发自己的架构。