Как я могу создать таблицу с уникальным именем и затем вставить данные из другой таблицы в эту таблицу, предпочтительно с помощью одного триггера - PullRequest
0 голосов
/ 14 января 2019

Я хочу иметь пустую таблицу, когда кто-то вставляет в нее данные, я хочу, чтобы эта таблица была немедленно скопирована в уникальное имя таблицы, а затем исходная таблица обрезана в готовности для повторения того же самого события.

Я попытался сделать это с помощью триггера, который затем выполняет процедуру, и я попытался сделать это только с помощью триггера, и у меня возникли проблемы с обоими.

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;

Этот «май» на самом деле работает, но я не могу запустить триггер, потому что «INSERT INTO V_TABLENAME» не будет работать, так как таблица еще не существует. Это первая часть моего кода, создайте уникальную таблицу, скопируйте все данные из исходной таблицы в нее после вставки.

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Это действительно не та вещь, которую мы должны делать в триггере. Есть некоторая сложная обработка, которой сложно управлять. Например, что должно произойти, если вы не можете создать триггер? Или если усечение не получится?

Это усугубляется запретом на выдачу коммитов в триггерах. Все операторы 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. Это кошмар обслуживания и поддержки.

Не зная деталей того, чего вы пытаетесь достичь, невозможно предложить лучший подход. Но будьте уверены, есть определенно лучшие подходы для вас.

0 голосов
/ 14 января 2019

Выполнить оператор вставки также с помощью команды «Выполнить немедленно», как показано ниже:

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;

Вы также можете проверить следующую ссылку, чтобы узнать, как использовать оператор немедленного выполнения. Выполнить немедленный пример

...