Триггер для расчета промежуточного итога

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

Здесь у меня есть три объекта (которые здесь имеют отношение): Customer_Order (всего и т. д.), Order_Line (количество, промежуточный итог и т. д.) и Products (запас, цена). 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

РЕДАКТИРОВАТЬ: я думаю, что мог бы использовать синтаксис :new для использования значения количества из оператора триггера. Я попробую это, но я был бы признателен за подтверждение и помощь, спасибо.


person Mo Moosa    schedule 07.12.2011    source источник


Ответы (2)


Похоже, вы хотите что-то вроде

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, в качестве виртуального столбца в таблице).

person Justin Cave    schedule 07.12.2011
comment
+1 за текст. (Я не тестировал код. В силу своеобразного поворота моих первых дней в проектировании баз данных у меня есть доступ к Oracle только дома.) - person Mike Sherrill 'Cat Recall'; 08.12.2011

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

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

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 в этом случае, должно быть довольно легко изменить вышеприведенное .)

person Dave Costa    schedule 07.12.2011