2016-01-23 1 views
0

Я пытаюсь создать триггер, но я узнал, что не могу его создать, как в первой попытке, которую я покажу ниже. Это приведет к ошибке «мутирующей таблицы» из-за выбора из таблицы по мере ее изменения. Это фактически не вызывало этой ошибки при вставке только одной записи за раз, но когда я вставляю сразу несколько записей, это происходит.Oracle SQL Создание триггера для увеличения номера последовательности для каждой строки

Целью триггера является подсчет количества записей в таблице, где клиент равен клиенту, который должен быть вставлен, и установить новое значение order_num как count + 1. У меня также есть значение открытого ключа, заданное триггером, который извлекается из последовательности. Эта часть работает нормально после удаления части order_num триггера и соответствующего SELECT. Как я могу достичь того, что я пытаюсь сделать здесь? Заранее спасибо.

CREATE OR REPLACE TRIGGER t_trg 
    BEFORE INSERT ON t 
    FOR EACH ROW 
DECLARE 
    rec_count NUMBER(2,0); 
    BEGIN 
    SELECT COUNT(*) INTO rec_count 
    FROM t 
    WHERE customer_id = :NEW.customer_id; 

    :NEW.order_num:= rec_count+1; 
    :NEW.order_pk_id:= table_seq.NEXTVAL; 

    END; 
+0

Несколько вопросов. Во-первых, почему вы пытаетесь сделать это вместо использования синтетического ключа (то есть последовательности)? Затем, если у вас есть действующая потребность, любое решение будет зависеть от профиля использования? Сколько клиентов? Сколько заказов на одного клиента? Можете ли вы обрабатывать несколько заказов на одного клиента одновременно? Какое время требуется? – APC

+0

Последовательность звучит великолепно, но тогда я считаю, что мне нужно будет создать новую последовательность для каждого нового клиента, который вставлен - приблизительно 100 К в год. Я использовал клиента, заказ и т. Д. Как абстракцию - я не имею дело с клиентами и заказами. У «клиента» никогда не будет> 1 «заказ» за партию - возможно, не в том же году. Следовательно, мой первоначальный подход подсчитывать только те, что есть в существующей таблице, и игнорировать то, что находится в обрабатываемой партии. В большинстве случаев у нескольких процентов будет 2+ «заказов» за всю жизнь. Моя самая большая проблема - время процессора, поскольку я делаю это на производственном сервере. – mb158127

+1

Почему вы подсчитываете строки каждый раз, когда вы вставляете строку? Это мертво медленно, не будет масштабироваться, но хуже всего: он будет хранить неправильное количество строк. Две параллельные транзакции получат ** то же ** значение в ': new.order_num'. –

ответ

0

Два подхода триггеров и временного стола могут обеспечить решение, которое вы ищете, предотвращая ошибочную ошибку таблицы. Однако производительность, скорее всего, пострадает.

create global temporary table cust_temp(customer_id number, cust_cnt number); 

create or replace trigger t_trig1 
before insert on t 
declare 
begin 
    insert into cust_temp select customer_id, count(*) from t group by customer_id; 
end; 
/

CREATE OR REPLACE TRIGGER t_trg2 
    BEFORE INSERT ON t 
    FOR EACH ROW 
DECLARE 
    rec_count number; 
    BEGIN 
    BEGIN 
     SELECT cust_cnt INTO rec_count 
     FROM cust_temp 
     WHERE customer_id = :NEW.customer_id; 
    EXCEPTION when no_data_found then rec_count := 0; 
    END; 
    :NEW.order_num:= rec_count+1; 
    :NEW.order_pk_id:= table_seq.NEXTVAL; 
     update cust_temp set cust_cnt = rec_count + 1 
     where customer_id = :NEW.customer_id; 

    END; 
/
Смежные вопросы