我想要一个空表,当有人向其中插入数据时,我希望该表立即复制到一个唯一的表名,然后将原始表截断以准备再次发生同样的事情。
我尝试使用触发器执行此操作,然后执行一个过程,而我尝试仅使用触发器执行此操作,但是我都遇到了问题。
CREATE OR REPLACE TRIGGER REPLICATE_PDU_TABLE
AFTER INSERT ON PDU
DECLARE V_TABLENAME VARCHAR2(30) := 'PDU_IN_PROGRESS_ || TO_CHAR(SYSDATE, 'YYYYMMDDHHMISS');
CURSOR C1 IS
SELECT * FROM PDU;
V_PDU C1%ROWTYPE;
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE ' || V_TABLENAME || ' AS SELECT * FROM PDU';
OPEN C1;
FETCH C1 INTO PDU ;
CLOSE C1;
INSERT INTO V_TABLENAME
VALUES (
V_PDU.TARGETSCHEMA,
V_PDU.PRODUCTIONSCHEMA,
V_PDU.PRODUCTIONDATABASE,
V_PDU.TABLE_NAME,
V_PDU.DRIVER_TABLE,
V_PDU.MANDATORY_JOIN,
V_PDU.ADDITIONAL_JOINS,
V_PDU.TABLE_COMPRESSION);
END TRIGGER REPLICATE_PDU_TABLE;
此“ May”实际上可以工作,但是我不能触发编译,因为“ INSERT INTO V_TABLENAME”将不起作用,因为该表尚不存在。这是我的代码的第一部分,创建一个唯一表,在插入后将所有数据从原始表复制到该表中。
答案 0 :(得分:2)
这实际上不是我们应该在触发器中执行的操作。有一些复杂的处理过程很难管理。例如,在无法创建触发器时应该发生什么?还是如果截断失败?
此外,禁止在触发器中发布提交也使情况更加复杂。所有DDL语句均发出提交(每个语句两个),因此从触发器中触发DDL语句的唯一方法是使用autonomous_transaction
编译指示。这是一个嵌套事务,这意味着它看不到表的当前内容。所以整个事情有点混乱。
这是一个思想实验,它说明了您需要做的事情:
create or replace trigger replicate_pdu_table
after insert on pdu
declare
-- note use the twenty-hour clock in mask
v_tablename varchar2(30) := 'PDU_IN_PROGRESS_' || to_char(sysdate, 'YYYYMMDDHH24MISS');
procedure create_table is
pragma autonomous_transaction;
begin
execute immediate 'create table ' || v_tablename || ' as select * from pdu where 1=2';
end create_table;
procedure truncate_pdu is
pragma autonomous_transaction;
begin
execute immediate 'truncate table pdu';
end truncate_pdu;
begin
create_table;
execute immediate 'insert into ' || v_tablename || ' select * from pdu';
truncate_pdu;
end;
/
问题是被截断:它会飞奔
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
当我们在pdu
中插入行时会触发触发器。也就是说,在我们可以发出提交之前。因此,主会话锁定了pdu
,因此自主事务无法进行截断。这绝对是触发器使用的障碍:您需要将其作为一个过程运行,可能是从轮询作业或通过队列调用的。
更广泛的问题是,为什么要这样做? 一种可动态创建表格的事务处理方法总是有气味的。除了泛滥的混乱模式之外,我在介绍中还提到了失败的风险。另外,使用创建表的进程将如何知道其名称?您的整个过程将基于动态SQL构建。这是维护和支持的噩梦。
如果不知道要实现的目标的详细信息,就不可能提出更好的方法。但是请放心,绝对有更好的方法可供您选择。
答案 1 :(得分:1)
还使用execute立即执行命令执行插入语句,如下所示:
CREATE OR REPLACE TRIGGER REPLICATE_PDU_TABLE
AFTER INSERT ON PDU
DECLARE V_TABLENAME VARCHAR2(30) := 'PDU_IN_PROGRESS_ || TO_CHAR(SYSDATE, 'YYYYMMDDHHMISS');
CURSOR C1 IS
SELECT * FROM PDU;
V_PDU C1%ROWTYPE;
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE ' || V_TABLENAME || ' AS SELECT * FROM PDU';
OPEN C1;
FETCH C1 INTO v_PDU ;
CLOSE C1;
EXECUTE IMMEDIATE '
INSERT INTO '|| V_TABLENAME || '
VALUES ( '||
V_PDU.TARGETSCHEMA ||','||
V_PDU.PRODUCTIONSCHEMA ||','||
V_PDU.PRODUCTIONDATABASE ||','||
V_PDU.TABLE_NAME ||','||
V_PDU.DRIVER_TABLE ||','||
V_PDU.MANDATORY_JOIN||','||
V_PDU.ADDITIONAL_JOINS ||','||
V_PDU.TABLE_COMPRESSION ||')';
END TRIGGER REPLICATE_PDU_TABLE;
您还可以检查以下链接,以了解如何使用execute立即语句。 Execute Immediate Example