在不枚举 PL/SQL 触发器中的列名的情况下,在更新之前将行复制到历史记录 table?
Copy row to history table before update without enumerating column names in PL/SQL trigger?
我正在尝试创建一个 PL/SQL 触发器,用于在行更新时将行的当前版本复制到历史记录 table 中。这可以像这样轻松完成:
CREATE OR REPLACE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
INSERT INTO bar_history VALUES bar.id = :old.id, bar.col1 = :old.col1 /* ...and so on */;
END;
但是,我想避免枚举所有列名,因为 tables bar
和 bar_history
是相同的,我不想每次都更新触发器我改了table。我尝试了两种方法,其中 none 有效。还有其他方法可以解决这个问题吗?
方法一:
CREATE OR REPLACE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
INSERT INTO bar_history VALUES :old;
END;
由于您显然不能将 :old
用作行类型(请参阅 this 问题),我收到以下错误消息:
PLS-00049: bad bind variable 'OLD'
方法二:
CREATE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
INSERT INTO bar_history
SELECT * FROM bar WHERE id = :old.id;
END;
这也给我一个错误:
ORA-04091: BAR is mutating, trigger/function may not see it
在这种情况下,您可以使用列表分区策略(一个用于当前 C 和历史 H)创建分区 table。您可以创建而不是触发器,如果 table 更新,记录将被插入并且现有记录状态将更新为 H - 隐式地将记录移动到历史分区。
您需要引用各个列。无法在触发器中引用整行。如果许多 table 都需要这个,或者您的 table 定义经常更改,您可以根据数据字典视图编写 pl/sql 来为您生成触发器。
更新:此处类似 question/answer:In an Oracle trigger, can I assign new and old to a rowtype variable?
有些人 运行 遇到过这种情况。
他们的方法——使用包全局变量来存储 rowid 和动态 select 列名在 after 语句触发器中。
https://community.oracle.com/message/370167
Tom Kyte 对此也有一些建议
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:734825535375
https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:59412348055
我正在尝试创建一个 PL/SQL 触发器,用于在行更新时将行的当前版本复制到历史记录 table 中。这可以像这样轻松完成:
CREATE OR REPLACE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
INSERT INTO bar_history VALUES bar.id = :old.id, bar.col1 = :old.col1 /* ...and so on */;
END;
但是,我想避免枚举所有列名,因为 tables bar
和 bar_history
是相同的,我不想每次都更新触发器我改了table。我尝试了两种方法,其中 none 有效。还有其他方法可以解决这个问题吗?
方法一:
CREATE OR REPLACE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
INSERT INTO bar_history VALUES :old;
END;
由于您显然不能将 :old
用作行类型(请参阅 this 问题),我收到以下错误消息:
PLS-00049: bad bind variable 'OLD'
方法二:
CREATE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
INSERT INTO bar_history
SELECT * FROM bar WHERE id = :old.id;
END;
这也给我一个错误:
ORA-04091: BAR is mutating, trigger/function may not see it
在这种情况下,您可以使用列表分区策略(一个用于当前 C 和历史 H)创建分区 table。您可以创建而不是触发器,如果 table 更新,记录将被插入并且现有记录状态将更新为 H - 隐式地将记录移动到历史分区。
您需要引用各个列。无法在触发器中引用整行。如果许多 table 都需要这个,或者您的 table 定义经常更改,您可以根据数据字典视图编写 pl/sql 来为您生成触发器。 更新:此处类似 question/answer:In an Oracle trigger, can I assign new and old to a rowtype variable?
有些人 运行 遇到过这种情况。 他们的方法——使用包全局变量来存储 rowid 和动态 select 列名在 after 语句触发器中。 https://community.oracle.com/message/370167
Tom Kyte 对此也有一些建议
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:734825535375 https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:59412348055