我怎样才能让它变得更好?

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_NOBILL 作为输入参数。然后您可以使用:new.BILL := YourFunction(:new.C_NO, :new.BILL); 调用该函数。这效率较低,因为函数调用总是会产生一点开销。但是,如果您也需要能够从其他地方调用此计算,则代码的集中化(以及因此的可维护性)应该优先考虑这种非常小的性能损失。

以上是关于我怎样才能让它变得更好?的主要内容,如果未能解决你的问题,请参考以下文章

我怎样才能使它成为一个更好的递归动画 jQuery 脚本?

自制力的本质是什么?怎样才能变得自律?

我怎样才能增加分数?

为啥这个 pg 查询这么慢?我怎样才能让它更快?

我怎样才能捕捉到视图变得可见

为啥 chr() 返回一个十六进制值,我怎样才能让它只返回字符 [重复]