2011-12-07 5 views
0

Я пытался реализовать этот триггер на некоторое время и добился прогресса (я думаю!), Но теперь я получаю ошибку мутации.Триггер для расчета промежуточного итога

У меня есть три объекта (которые здесь актуальны), Customer_Order (всего и т. Д.), Order_Line (количество, промежуточный итог и т. Д.) И Продукты (акции, цена). Order_line - это объект связи, поэтому продукт может быть во многих order_lines, а customer_order может иметь много order_lines, но order_line может появляться только один раз в заказе и может содержать только один продукт. Цель триггера - взять промежуточный итог от order_line (или цены от продуктов, которые, как мне кажется, на самом деле), и количества из order_line, умножить их и обновить промежуточный итог новой order_line.

Поэтому я вставляю order_line с моим внешним ключом продукта, количеством 3 и ценой 4,00, триггер умножает два на равные 12 и обновляет промежуточный итог. Теперь я думаю, что правильно использовать цену здесь вместо промежуточного итога Order_line, чтобы исправить ошибку мутации (что происходит из-за того, что я прошу триггер обновить таблицу, к которой обращается оператор триггера, правильно?), Но как я могу исправить проблему с количеством? Количество не всегда будет тем же значением, что и акции, оно должно быть меньше или равно запасу, так что кто-нибудь знает, как я могу исправить это, чтобы выбрать из продукта и обновить order_line? Благодарю.

CREATE OR REPLACE TRIGGER create_subtotal 
BEFORE INSERT OR UPDATE ON Order_Line 
for each row 
DECLARE 
currentSubTotal order_line.subtotal%type; 
currentQuantity order_line.quantity%type; 
BEGIN 
select order_line.subtotal,order_line.quantity 
into currentSubTotal,currentQuantity 
from order_line 
where product_no = :new.product_no; 
IF (currentquantity>-1) then 

update order_line set subtotal= currentSubTotal * currentQuantity where  line_no=:new.line_no; 

END IF; 
END; 
. 
run 

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

ответ

1

это звучит, как вы хотите что-то вроде

CREATE OR REPLACE TRIGGER create_subtotal 
    BEFORE INSERT OR UPDATE ON order_line 
    FOR EACH ROW 
DECLARE 
    l_price products.price%type; 
BEGIN 
    SELECT price 
    INTO l_price 
    FROM products 
    WHERE product_no = :new.product_no; 

    IF(:new.quantity > -1) 
    THEN 
    :new.subtotal := :new.quantity * l_price; 
    END IF; 
END; 

Если это нечто иное, чем домашняя работа, однако, на самом деле не имеет смысла тянуть цену с таблицы PRODUCTS в этом триггере. Предположительно, цена продукта будет меняться со временем. Но цена фиксируется для определенного порядка при размещении заказа. Если триггер был определен только на INSERT, вероятно, было бы разумно просто выбрать текущую цену. Но если вы хотите пересчитать промежуточный итог строки при обновлении строки, вам нужно будет получить цену с момента размещения заказа (и предполагается, что вы не взимаете с разных клиентов разные цены при том же время).

С точки зрения нормализации, оно также имеет тенденцию не иметь смысла хранить рассчитанные поля в первую очередь. Было бы разумнее хранить количество и цену в таблице order_line, а затем рассчитать промежуточный итог для строки в представлении (или, если вы используете 11g, в качестве виртуального столбца в таблице).

+0

+1 для текста. (Я не тестировал код. В своеобразный поворот к моим ранним дням в дизайне базы данных у меня есть только доступ к Oracle * дома *). –

1

Ошибка мутации не возникает из-за обновления таблицы; это происходит потому, что вы запрашиваете из таблицы, которая уже обновляется.

Если я правильно понять, что вы хотите сделать:

CREATE OR REPLACE TRIGGER create_subtotal 
BEFORE INSERT OR UPDATE ON Order_Line 
for each row 
DECLARE 
    currentPrice products.price%TYPE; 
BEGIN 
    -- Get the current price for the product 
    SELECT price INTO currentPrice FROM products WHERE product_no = :new.product_no; 

    -- Set the new subtotal to the current price multiplied by the order quantity 
    :new.subtotal := currentPrice * :new.quantity; 
END; 
/

(я не ясно, почему у вас есть тест на величину ниже 0, и то, что вы хотите, чтобы произойти в этом случае если. вы хотите установить подытог в NULL или 0 в этом случае, она должна быть достаточно легко модифицировать выше.)

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