0

下面我创建了 2 个应用折扣的触发器,一个使用功能而另一个不使用。有没有其他方法可以提高效率/更好?

 CREATE OR REPLACE TRIGGER APPLY_DISCOUNT
 BEFORE INSERT OR UPDATE OF INV_NO,C_NO ON INVOICE
 FOR EACH ROW

 DECLARE

 CURSOR C_APPTMNT
 IS
 SELECT C_NO,COUNT(C_NO) 
 FROM APPOINTMENT GROUP BY C_NO;

 V_C_NO APPOINTMENT.C_NO%TYPE;
 VISIT NUMBER(2);

 BEGIN

 VISIT:=CNT_VISIT(:NEW.C_NO);

 IF VISIT BETWEEN 2 AND 4 
 AND :NEW.C_NO = V_C_NO THEN
 :NEW.BILL := :NEW.BILL * 0.9;

 ELSIF VISIT BETWEEN 5 AND 8 
 AND :NEW.C_NO = V_C_NO THEN
 :NEW.BILL := :NEW.BILL * 0.8;

 ELSIF VISIT >=9 AND :NEW.C_NO = V_C_NO THEN:NEW.BILL := :NEW.BILL * 0.7;

 ELSE DBMS_OUTPUT.PUT_LINE('no discount added');

 END IF;

 CLOSE C_APPTMNT;
 END;
 /

///////////////////////////////////////// //////////////

 CREATE OR REPLACE FUNCTION ADD_DISCOUNT(
 I_C_NO INVOICE.C_NO%TYPE, I_BILL INVOICE.BILL%TYPE)
 RETURN NUMBER
 IS
 V_BILL invoice.bill%type;

 CURSOR C_APPTMNT
 IS
SELECT C_NO,COUNT(C_NO)
 FROM APPOINTMENT GROUP BY C_NO;

V_C_NO INVOICE.C_NO%TYPE;
VISIT NUMBER;

BEGIN

OPEN C_APPTMNT;
FETCH C_APPTMNT INTO V_C_NO,VISIT;

 IF VISIT >=3
AND I_C_NO = V_C_NO THEN
V_BILL := I_BILL * 0.9;

ELSIF VISIT >=6
AND I_C_NO = V_C_NO THEN
V_BILL := I_BILL * 0.8;

 ELSIF VISIT >=9 AND I_C_NO = V_C_NO THEN V_BILL := I_BILL * 0.7;
 ELSE V_BILL:= I_BILL;
END IF;

CLOSE C_APPTMNT;

RETURN V_BILL;

END;
/


CREATE OR REPLACE TRIGGER DIS_BILL
BEFORE INSERT OR UPDATE OF INV_NO,C_NO ON INVOICE
FOR EACH ROW
DECLARE
BEGIN
:NEW.BILL:=ADD_DISCOUNT(:NEW.C_NO,:NEW.BILL);
END;
/
4

1 回答 1

1

第二个是错误的。如果一个值是>= 9它也是>=6>=3。因此,永远不会达到其他那些。

在第一个中,您编写输出,但前提是没有添加折扣。感觉就像你只是把那行放在那里,因为没有它就无法编译,但你也可以添加一行 containsnull;来制作一个空语句块编译。

还有更多技巧可以使此触发器更快。一方面,您不必查询所有记录,因为您知道该组。您可以在查询中进行计算,尽管这不会使其更快。

您的触发器可能如下所示:

CREATE OR REPLACE TRIGGER APPLY_DISCOUNT
  BEFORE INSERT OR UPDATE OF INV_NO, C_NO ON INVOICE
  FOR EACH ROW

BEGIN

  SELECT 
    CASE 
      WHEN COUNT(C_NO) >= 9 THEN 0.7
      WHEN COUNT(C_NO) >= 6 THEN 0.8
      WHEN COUNT(C_NO) >= 3 THEN 0.9
    ELSE 1
    END * :NEW.BILL
  INTO
    :NEW.BILL
  FROM 
   APPOINTMENT 
  WHERE
    C_NO = :NEW.C_NO;

END;
/

我认为SELECT INTO :NEW.BILL应该可以,但如果没有,您可以将其选择为变量,然后将其分配给:NEW.BILL.

于 2012-11-25T21:55:32.170 回答