Below i have created 2 triggers that apply a discount, one uses a function while the other does not. Is there any other way to make this efficient/better?
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;
/
The second one is wrong. If a value is
>= 9it is also>=6and>=3. Therefore, those elses will never be reached.In the first one, you write output, but only if no discount was added. It feels like you just put that line there because it won’t compile without it, but you can also add a line containing
null;to make an empty statement block compiling.There are more tricks to make this trigger faster. For one, you don’t have to query all records, since you know the group. And you can do the calculation in the query, although that won’t make it much faster.
Your trigger could look like this:
I think
SELECT INTO :NEW.BILLshould work, but if not, you could select it into a variable and then assign it to:NEW.BILL.