我怎样才能让它变得更好?
Posted
技术标签:
【中文标题】我怎样才能让它变得更好?【英文标题】:How can i make this better? 【发布时间】:2012-11-25 21:42:43 【问题描述】:下面我创建了 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;
/
【问题讨论】:
您是否在问哪种方法最有效地满足此要求?即触发器或函数? @w0051977 是的,上面哪个更好用 @w0051977 得到了我的答案,感谢您的帮助 【参考方案1】:第二个是错的。如果一个值为>= 9
,它也是>=6
和>=3
。因此,永远不会达到其他那些。
在第一个中,您编写输出,但前提是没有添加折扣。感觉就像你只是把那一行放在那里,因为没有它就无法编译,但你也可以添加一行包含 null;
的行来创建一个空语句块编译。
还有更多技巧可以让这个触发器更快。一方面,您不必查询所有记录,因为您知道该组。并且您可以在查询中进行计算,尽管这不会使其更快。
您的触发器可能如下所示:
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
。
【讨论】:
感谢您的帮助,有什么方法可以在触发器中包含一个函数。此外,每 3 次访问、6 次访问和 9 次访问都给予折扣。 你可以包含一个函数,但我不确定你在问什么。 感谢您的回复,我可以在函数中进行选择计数和应用折扣等吗?这会提高效率吗? 你可以这样做。您可以将SELECT INTO
移动到一个函数中,该函数具有C_NO
和BILL
作为输入参数。然后您可以使用:new.BILL := YourFunction(:new.C_NO, :new.BILL);
调用该函数。这效率较低,因为函数调用总是会产生一点开销。但是,如果您也需要能够从其他地方调用此计算,则代码的集中化(以及因此的可维护性)应该优先考虑这种非常小的性能损失。以上是关于我怎样才能让它变得更好?的主要内容,如果未能解决你的问题,请参考以下文章