Проблема Oracle Trigger Subquery - PullRequest
       19

Проблема Oracle Trigger Subquery

1 голос
/ 22 сентября 2011
CREATE OR REPLACE TRIGGER "DISC_CLIENT"
BEFORE INSERT ON "PURCHASE"
FOR EACH ROW
DECLARE
checkclient PURCHASE.CLIENTNO%TYPE;
BEGIN
SELECT Clientno INTO checkclient
FROM PURCHASE
GROUP BY ClientNo
HAVING SUM(Amount)=(SELECT MAX(SUM(Amount)) FROM PURCHASE GROUP BY Clientno);
IF :new.ClientNo = checkclient
new.Amount := (:old.Amount * 0.90);
END IF;
END;
/

Кажется, у вас проблемы с этим триггером. Я знаю, что не могу использовать предложение WHEN () для подзапросов, так что я надеюсь, что это будет работать, но это не так! Идеи кого-нибудь? : /

По сути, я пытаюсь заставить этот триггер применить скидку к значению суммы перед вставкой, если клиент соответствует топ-клиенту! :)

Ответы [ 2 ]

2 голосов
/ 22 сентября 2011

Есть нехороший, но простой способ обойти это, создать вид и обновить его.Затем вы можете явно указать все столбцы в вашем триггере и поместить их в таблицу.Вам также было бы гораздо лучше создать таблицу из 1 строки с 2 столбцами, max_amount, а затем вставлять в нее максимальную сумму и clientno каждый раз.Вы также должны иметь столбец со скидкой в ​​таблице покупок, так как вы должны знать, кому вы предоставили скидки.В таком случае взимается сумма amount - discount.Это позволяет справиться как с таблицей мутаций, так и с невозможностью обновления :new.amount, а также с намного более быстрыми запросами.В сущности, вы фактически не применяете скидку, если текущая транзакция является самой высокой, только если клиент установил предыдущее самое высокое, поэтому я написал это так.

create or replace view purchase_view as
  select *
    from purchase;

CREATE OR REPLACE TRIGGER TR_PURCHASE_INSERT
  BEFORE INSERT ON PURCHASE_VIEW
  FOR EACH ROW

  DECLARE

  checkclient max_amount.clientno%type;
  checkamount max_amount.amount%type;
  discount    purchase.discount%type;

  BEGIN

    SELECT clientno, amount
      INTO checkclient, checkamount
      FROM max_amount;

   IF :new.clientno = checkclient then
      discount := 0.1 * :new.amount;
   ELSIF :new.amount > checkamount then
      update max_amount
         set clientno = :new.clientno
           , maxamount = :new.amount
             ; 
    END IF;

    -- Don-t specify columns so it breaks if you change
    -- the table and not the trigger
    insert into purchase 
    values ( :new.clientno
           , :new.amount
           , discount
           , :new.other_column );
END TR_PURCHASE_INSERT;
/
1 голос
/ 22 сентября 2011

Как я помню, триггер не может выбрать из таблицы, для которой он запущен.В противном случае вы получите ORA-04091: таблица XXXX мутирует, триггер / функция может ее не увидеть.Том советует нам не вкладывать слишком много логики в триггеры.

И если я понимаю ваш запрос, он должен выглядеть следующим образом:

SELECT Clientno INTO checkclient
FROM PURCHASE
GROUP BY ClientNo
HAVING SUM(Amount)=(select max (sum_amount) from (SELECT SUM(Amount) as sum_amount FROM PURCHASE GROUP BY Clientno));

Таким образом, это будетверните клиента, который потратил больше всего денег.

Но я думаю, что лучше сделать это так:

select ClientNo
from (
  select ClientNo, sum (Amount) as sum_amount
  from PURCHASE
  group by ClientNo)
order by sum_amount
where rownum 
...