2016-06-17 2 views
0

У меня есть система, на которую люди заказывают, каждый порядок имеет действия, а таблица существует как cm_ord_order_action. Иногда действия терпят неудачу, поэтому мне нужно создать триггер, который получает информацию о неудавшемся действии заказа и заполняет таблицу с именем cm_ord_failed_order.Таблица не обновлена ​​триггером и процедурой

триггером приведена ниже:

CREATE OR REPLACE TRIGGER CM.TRGID_CM_ORD_FAILED_ORDER 
AFTER UPDATE ON CM.CM_ORD_ORDER_ACTION 
FOR EACH ROW 
BEGIN 
    IF (:new.STATUS = 'FA') THEN 
     CM.CM_FAILED_ORDER_MLT(:new.order_unit_id, :new.order_id, :new.action_type); 
    END IF; 
END; 
/

Этот триггер передает параметры в процедуру, которая обновляет таблицу:

CREATE OR REPLACE PROCEDURE CM_FAILED_ORDER_MLT(
v_order_unit_id NUMBER, 
v_order_id in NUMBER, 
v_action_type in VARCHAR) 

AS 
v_lob varchar(100); 
v_step varchar(100); 
v_error varchar(200); 

BEGIN 

SELECT 
    ITEM.LOB_NAME, ST.STEP_NAME, ASS.STEP_ERROR 
    INTO v_lob, v_step, v_error   
FROM 
    CM.CM_ORD_ORDER_ACTION OA 
    INNER JOIN CM.CM_ORD_ASSIGNMENTS ASS 
     ON OA.ORDER_UNIT_ID = ASS.ORDER_ACTION_ID 
    INNER JOIN CM.CM_ORD_PROCESS_STEP ST 
     ON ST.ORD_PROCESS_STEP_ID = ASS.STEP_ID 
    INNER JOIN CM.CM_ORD_AP_ITEM ITEM 
     ON ITEM.AP_SUBSCRIBER_ID = OA.AP_SUBSCRIBER_ID 
WHERE ASS.COMPLETION_STATUS = 'FA' 
AND OA.ORDER_ID = v_order_id 
AND OA.ORDER_UNIT_ID = v_order_unit_id 
GROUP BY OA.ORDER_UNIT_ID, ITEM.LOB_NAME, ST.STEP_NAME, ASS.STEP_ERROR; 

INSERT INTO CM_ORD_FAILED_ORDER (ORDER_ID, FAILED_DATE, ORDER_ACTION_ID, ACTION_TYPE, LOB, STEP, ERROR) 
    VALUES (v_order_id, sysdate, v_order_unit_id, v_action_type, v_lob, v_step, v_error); 

END CM_FAILED_ORDER_MLT; 
/

Там, вероятно, что-то здесь не так, потому что: A - Даже несмотря на то, триггер - после обновления на cm_ord_order_action, когда триггер включен, статус не обновляется, но когда я отключу триггер, статус обновляется.

B - таблица cm_ord_failed_order не заполняется информацией.

Заранее благодарен.

+0

Почему бы не использовать перед обновлением? – kevinsky

+1

Как выполняется обновление? Является ли процедура выдачей исключения (данные не найдены?), Который запускает триггер, но который, возможно, сжимается/игнорируется тем, что делает обновление? Вы пытались сделать обновление вручную, чтобы узнать, что произойдет, или отладить? –

+1

Я предполагаю, что ваш триггер вызывает ошибку. Я предполагаю, что это ошибка таблицы с ошибками. Это то, что вы на самом деле видите? У вас есть часть кода, которая проглатывает эти ошибки? Я ожидал бы, что вы захотите удалить ссылку на 'CM_ORD_ORDER_ACTION' из своей процедуры - вам нужно будет передать все значения из этой таблицы, которые вам нужны из триггера. –

ответ

1

Вы можете избежать ошибки, связанной с изменением таблицы, которую ваш скрипт каким-то образом игнорирует или отбрасывает, делая вставку непосредственно в триггере, где у вас есть данные из строки, обновляемой в псевдослуке :NEW, и не нужно запрашивать ее снова , Вы также можете сделать insert...select, не требуя локальных переменных.

Я думаю, что это грубый перевод:

CREATE OR REPLACE TRIGGER CM.TRGID_CM_ORD_FAILED_ORDER 
AFTER UPDATE ON CM.CM_ORD_ORDER_ACTION 
FOR EACH ROW 
WHEN (new.STATUS = 'FA') 
BEGIN 

    INSERT INTO CM_ORD_FAILED_ORDER (ORDER_ID, FAILED_DATE, ORDER_ACTION_ID, ACTION_TYPE, 
    LOB, STEP, ERROR) 
    SELECT 
    DISTINCT :new.ORDER_ID, sysdate, :new.Order_Unit_Id, :new.Action_Type, 
     ITEM.LOB_NAME, ST.STEP_NAME, ASS.STEP_ERROR 
    FROM 
    CM.CM_ORD_ASSIGNMENTS ASS 
    INNER JOIN CM.CM_ORD_PROCESS_STEP ST 
     ON ST.ORD_PROCESS_STEP_ID = ASS.STEP_ID 
    CROSS JOIN CM.CM_ORD_AP_ITEM ITEM 
    WHERE ASS.ORDER_ACTION_ID = :new.ORDER_UNIT_ID 
    AND ASS.COMPLETION_STATUS = :new.STATUS 
    AND ITEM.AP_SUBSCRIBER_ID = :new.AP_SUBSCRIBER_ID; 

END CM_FAILED_ORDER_MLT; 
/

DISTINCT (вместо группировки) и CROSS JOIN предложить вам не хватает условие соединения в исходном запросе, но без табличных структур и данных, которые могут не так.

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

Ваш триггер также может быть BEFORE UPDATE, а не AFTER UPDATE.

+1

Я предполагаю, что в первую очередь OP включала таблицу 'cm.cm_ord_order_action' в запросе, потому что cm_ord_ap_item не был присоединен ни к одной из других таблиц этого запроса. Тем не менее, есть более чем один способ обмануть этого кота! * {;-) – Boneist

0

Как @JustinCave сказал, это ясно, что вы мутируете таблицу error:

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

На триггере CM_ORD_ORDER_ACTION вы выбираете из той же таблицы. Попробуйте повторить запрос в процедуре без ссылки на CM_ORD_ORDER_ACTION.

1

Альтернативой решения Алекса, что исключает необходимость перекрестного соединения будет изменить процедуру:

create or replace procedure cm_failed_order_mlt (v_order_unit_id number, 
               v_order_id in number, 
               v_action_type in varchar, 
               v_ap_subscriber_id in cm.cm_ord_order_action.ap_subscriber_id%type) 

as 
    v_lob varchar(100); 
    v_step varchar(100); 
    v_error varchar(200); 
begin 
    select distinct lob_name 
    into v_lob 
    from cm.cm_ord_ap_item 
    where ap_subscriber_id = v_ap_subscriber_id; 

    select distinct st.step_name, ass.step_error 
    into v_step, v_error   
    from cm.cm_ord_assignments ass 
     inner join cm.cm_ord_process_step st on st.ord_process_step_id = ass.step_id 
    where ass.completion_status = 'FA' 
    and ass.order_action_id = v_order_id 
    and oa.order_unit_id = v_order_unit_id; 

    insert into cm_ord_failed_order (order_id, failed_date, order_action_id, action_type, lob, step, error) 
    values (v_order_id, sysdate, v_order_unit_id, v_action_type, v_lob, v_step, v_error); 

end cm_failed_order_mlt; 
/

Или, чтобы удалить перекрестное соединение в растворе Алекса, просто заменить его скалярный подзапрос , например:

select (select distinct lob_name from cm.cm_ord_ap_item where ap_subscriber_id = v_ap_subscriber_id), ... 
+1

I * suspect * первый запрос получит несколько строк, и это то, что требовало, чтобы исходный запрос имел предложение group-by, поэтому вместо этого я оставил здесь 'distinct'. Но без таблиц/данных я размышляю дико. Возможно, группировка была избыточной, или дубликаты могли появляться откуда-то еще ... –

+0

ах да, хороший момент. Я также добавлю в этот запрос отличный результат - я предполагаю из основного запроса, что возвращается не более 1 строки. И теперь, когда вы упомянули об этом, я включу группу во втором запросе и в отдельную. – Boneist

Смежные вопросы