Home » SQL & PL/SQL » SQL & PL/SQL » After/Before Insert Trigger (SQL Plus 9i)
After/Before Insert Trigger [message #309759] |
Fri, 28 March 2008 12:31 |
jay565260
Messages: 9 Registered: March 2008
|
Junior Member |
|
|
Hi
iam trying to generate an after insert trigger for a student monitoring system which counts the number of "behavoiurs" for a particular student and places the value in a packaged variable. Then the variable is placed into an IF statement, if the student recieves 2 "behaviours" Lunch time detention 3 "behaviours" After school detention. My problem is the trigger flags up a detention on the row after, i.e 2 "behaviours" inserted-No message flag, on the next insert-Lunch Time Detention msg appears. Is there a way round this so that on the 2nd insert of a "behaviour" u get the lunchtime detention msg, and likewise for 3 "behaviours" ive tried using both Before and After Insert Triggers and still no luck.
Until i can get round this i cant move forward and ive been trying for 3 days,would really appreciate any assistance.
Thanks
Jay
--Convert to a packaged procedure
CREATE OR REPLACE PACKAGE behav_pkg AS
pv_beh_total NUMBER (8);
pv_date DATE;
pv_stu NUMBER (10);
pv_class NUMBER (10);
pv_punish VARCHAR2(40);
END;
/
--Create statement level trigger
--DROP TRIGGER check_det_trg;
CREATE OR REPLACE TRIGGER check_det_trg
AFTER INSERT ON behaviour
BEGIN
SELECT COUNT(behaviour_id)
INTO behav_pkg.pv_beh_total
FROM behaviour
WHERE be_stu_id =behav_pkg.pv_stu
AND be_class_id = behav_pkg.pv_class
AND date_recieved =behav_pkg.pv_date;
END;
/
--Create row level trigger
--DROP TRIGGER check_beh_trg;
CREATE OR REPLACE TRIGGER check_beh_trg
BEFORE INSERT ON behaviour
FOR EACH ROW
BEGIN
IF behav_pkg.pv_beh_total = 2 THEN
behav_pkg.pv_punish:='Lunch Time Detension';
DBMS_OUTPUT.PUT_LINE(behav_pkg.pv_punish);
--some kind of insert into detension detail
ELSIF behav_pkg.pv_beh_total = 3 THEN
behav_pkg.pv_punish:='After School Detension';
DBMS_OUTPUT.PUT_LINE(behav_pkg.pv_punish);
behav_pkg.pv_beh_total:=0;
behav_pkg.pv_stu:=0;
behav_pkg.pv_class:=0;
DBMS_OUTPUT.PUT_LINE(behav_pkg.pv_stu);
DBMS_OUTPUT.PUT_LINE(behav_pkg.pv_class);
DBMS_OUTPUT.PUT_LINE(behav_pkg.pv_beh_total);
--some kind of insert into detension detail
END IF;
END;
/
--Test Trigger firstly initialize statement level trigger with the student and class id
BEGIN
behav_pkg.pv_stu:=5;
END;
/
BEGIN
behav_pkg.pv_class:=3;
END;
/
BEGIN
behav_pkg.pv_date:='27-Mar-08';
END;
/
INSERT INTO behaviour values (11, 'Equipment', 1, 2, '27-Mar-08');
INSERT INTO behaviour values (12, 'Equipment', 2, 4, '27-Mar-08');
INSERT INTO behaviour values (13, 'Equipment', 5, 3, '27-Mar-08');
INSERT INTO behaviour values (14, 'Equipment', 5, 3, '27-Mar-08');
INSERT INTO behaviour values (15, 'Behaviour', 5, 3, '27-Mar-08');
INSERT INTO behaviour values (16, 'Equipment', 5, 3, '27-Mar-08');
[Updated on: Fri, 28 March 2008 13:27] by Moderator Report message to a moderator
|
|
|
Re: After/Before Insert Trigger [message #309764 is a reply to message #309759] |
Fri, 28 March 2008 13:26 |
|
Michel Cadot
Messages: 68722 Registered: March 2007 Location: Saint-Maur, France, https...
|
Senior Member Account Moderator |
|
|
I don't understand what you want to do but complex logic MUST be executed by procedures and NOT, NEVER by triggers.
In addition, '27-Mar-08' is NOT a date but a STRING.
Also please read OraFAQ Forum Guide, especially "How to format your post?" section.
Make sure that lines of code do not exceed 80 characters when you format.
Indent the code (See SQL Formatter) and align the columns in result.
Use the "Preview Message" button to verify.
This time I did it for you, next time do it yourself.
Always post your Oracle version (4 decimals).
Regards
Michel
[Updated on: Fri, 28 March 2008 13:27] Report message to a moderator
|
|
|
Re: After/Before Insert Trigger [message #309864 is a reply to message #309764] |
Sat, 29 March 2008 07:39 |
jay565260
Messages: 9 Registered: March 2008
|
Junior Member |
|
|
What i want the trigger to do is, count the number of behaviors inserted into the behaviour table for a particular student, class and date.
IF the student receives 2 behaviours, generate a msg stating Lunch time detention. Currently the code generates this msg on the insert after i.e.
INSERT INTO behaviour values (13, 'Equipment', 5, 3, '27-Mar-08');
INSERT INTO behaviour values (14, 'Equipment', 5, 3, '27-Mar-08');
[b](I want the msg to appear after this insert because student 5 has received to behaviours)[/b]
INSERT INTO behaviour values (15, behaviour, 1, 4, '27-Mar-08');
[b]Lunch Time Detention[/b]
I have tried using both Before and After triggers. Any suggestions would be great thanks.
|
|
|
Re: After/Before Insert Trigger [message #309873 is a reply to message #309764] |
Sat, 29 March 2008 09:23 |
jay565260
Messages: 9 Registered: March 2008
|
Junior Member |
|
|
I have taken your good advice to turn the trigger function into a procedure. The procedure works when you execute it on its own however iam now getting the table is mutating error when calling it from the trigger. Can you suggest any work arounds im completly stuck.
Thanks
CREATE OR REPLACE PROCEDURE school_det_sp
(s_id IN behaviour.be_stu_id%TYPE,
c_id IN behaviour.be_class_id%TYPE,
d_id IN behaviour.date_recieved%TYPE)
IS
lv_beh_total NUMBER (8);
lv_punish VARCHAR2(40);
BEGIN
SELECT COUNT(behaviour_id)
INTO lv_beh_total
FROM behaviour
WHERE be_stu_id =s_id
AND be_class_id = c_id
AND date_recieved =d_id;
IF lv_beh_total = 2 THEN
lv_punish:='Lunch Time Detension';
DBMS_OUTPUT.PUT_LINE(lv_punish);
--some kind of insert into detension detail
ELSIF lv_beh_total = 3 THEN
lv_punish:='After School Detension';
DBMS_OUTPUT.PUT_LINE(lv_punish);
--some kind of insert into detension detail
END IF;
END;
/
EXECUTE school_det_sp (5,3,'29-MAR-08');
--Call the procedure from a trigger
CREATE OR REPLACE TRIGGER school_det_trg
AFTER INSERT ON behaviour
FOR EACH ROW
BEGIN
school_det_sp(:NEW.be_stu_id, :NEW.be_class_id, :NEW.date_recieved);
END;
/
[Updated on: Sat, 29 March 2008 09:25] Report message to a moderator
|
|
|
|
Re: After/Before Insert Trigger [message #309880 is a reply to message #309874] |
Sat, 29 March 2008 10:37 |
jay565260
Messages: 9 Registered: March 2008
|
Junior Member |
|
|
Are you being rude on purpose? i am new to this site ok, i have searched around this forum and on google for the last few days and i am struggling with the issue stated and require some guidance. If you don't want to help or have any positive suggestions, please keep your patronising comments to yourself.
|
|
|
|
|
|
|
Re: After/Before Insert Trigger [message #309891 is a reply to message #309890] |
Sat, 29 March 2008 12:00 |
|
Barbara Boehmer
Messages: 9100 Registered: November 2002 Location: California, USA
|
Senior Member |
|
|
There are different philosophies on this subject. Some advocate control through procedures only without triggers and no other access such as SQL*Plus. However, if anybody, even a developer or DBA, inserts through SQL*Plus instead of a through a procedure, and I have seen this happen too many times, then you have a mess. So, I tend to prefer to use triggers. I might maintain the count in a separate table as shown below.
SCOTT@orcl_11g> CREATE TABLE behaviour
2 (behaviour_id NUMBER,
3 be_stu_id NUMBER,
4 be_class_id NUMBER,
5 date_received DATE)
6 /
Table created.
SCOTT@orcl_11g> CREATE TABLE behav_count
2 (be_stu_id NUMBER,
3 be_class_id NUMBER,
4 date_received DATE,
5 beh_total NUMBER)
6 /
Table created.
SCOTT@orcl_11g> CREATE TABLE detention
2 (be_stu_id NUMBER,
3 be_class_id NUMBER,
4 date_received DATE,
5 behaviors NUMBER,
6 punishment VARCHAR2 (25))
7 /
Table created.
SCOTT@orcl_11g> CREATE OR REPLACE TRIGGER behaviour_air
2 AFTER INSERT ON behaviour
3 FOR EACH ROW
4 DECLARE
5 v_count NUMBER;
6 BEGIN
7 SELECT bc.beh_total + 1
8 INTO v_count
9 FROM behav_count bc
10 WHERE bc.be_stu_id = :NEW.be_stu_id
11 AND bc.be_class_id = :NEW.be_class_id
12 AND bc.date_received = :NEW.date_received;
13 IF v_count = 2 THEN
14 UPDATE behav_count bc
15 SET bc.beh_total = beh_total + 1
16 WHERE bc.be_stu_id = :NEW.be_stu_id
17 AND bc.be_class_id = :NEW.be_class_id
18 AND bc.date_received = :NEW.date_received;
19 DBMS_OUTPUT.PUT_LINE (:NEW.be_stu_id || ' has ' || v_count || ' behaviors - lunch detention');
20 INSERT INTO detention (be_stu_id, be_class_id, date_received, behaviors, punishment)
21 VALUES (:NEW.be_stu_id, :NEW.be_class_id, :NEW.date_received, v_count, 'lunch detention');
22 ELSIF v_count = 3 THEN
23 UPDATE behav_count bc
24 SET bc.beh_total = beh_total + 1
25 WHERE bc.be_stu_id = :NEW.be_stu_id
26 AND bc.be_class_id = :NEW.be_class_id
27 AND bc.date_received = :NEW.date_received;
28 DBMS_OUTPUT.PUT_LINE (:NEW.be_stu_id || ' has ' || v_count || ' behaviors - after school detention');
29 INSERT INTO detention (be_stu_id, be_class_id, date_received, behaviors, punishment)
30 VALUES (:NEW.be_stu_id, :NEW.be_class_id, :NEW.date_received, v_count, 'after school detention');
31 END IF;
32 EXCEPTION
33 WHEN NO_DATA_FOUND THEN
34 INSERT INTO behav_count VALUES
35 (:NEW.be_stu_id, :NEW.be_class_id, :NEW.date_received, 1);
36 END behaviour_air;
37 /
Trigger created.
SCOTT@orcl_11g> SHOW ERRORS
No errors.
SCOTT@orcl_11g> INSERT INTO behaviour values (11, 1, 2, TRUNC (SYSDATE))
2 /
1 row created.
SCOTT@orcl_11g> INSERT INTO behaviour values (12, 2, 4, TRUNC (SYSDATE))
2 /
1 row created.
SCOTT@orcl_11g> INSERT INTO behaviour values (13, 5, 3, TRUNC (SYSDATE))
2 /
1 row created.
SCOTT@orcl_11g> INSERT INTO behaviour values (14, 5, 3, TRUNC (SYSDATE))
2 /
5 has 2 behaviors - lunch detention
1 row created.
SCOTT@orcl_11g> INSERT INTO behaviour values (15, 1, 2, TRUNC (SYSDATE))
2 /
1 has 2 behaviors - lunch detention
1 row created.
SCOTT@orcl_11g> INSERT INTO behaviour values (16, 5, 3, TRUNC (SYSDATE))
2 /
5 has 3 behaviors - after school detention
1 row created.
SCOTT@orcl_11g> SELECT * FROM behaviour
2 /
BEHAVIOUR_ID BE_STU_ID BE_CLASS_ID DATE_RECE
------------ ---------- ----------- ---------
11 1 2 29-MAR-08
12 2 4 29-MAR-08
13 5 3 29-MAR-08
14 5 3 29-MAR-08
15 1 2 29-MAR-08
16 5 3 29-MAR-08
6 rows selected.
SCOTT@orcl_11g> SELECT * FROM behav_count
2 /
BE_STU_ID BE_CLASS_ID DATE_RECE BEH_TOTAL
---------- ----------- --------- ----------
1 2 29-MAR-08 2
2 4 29-MAR-08 1
5 3 29-MAR-08 3
SCOTT@orcl_11g> SELECT * FROM detention
2 /
BE_STU_ID BE_CLASS_ID DATE_RECE BEHAVIORS PUNISHMENT
---------- ----------- --------- ---------- -------------------------
5 3 29-MAR-08 2 lunch detention
1 2 29-MAR-08 2 lunch detention
5 3 29-MAR-08 3 after school detention
SCOTT@orcl_11g>
|
|
|
Re: After/Before Insert Trigger [message #309893 is a reply to message #309891] |
Sat, 29 March 2008 12:18 |
|
Michel Cadot
Messages: 68722 Registered: March 2007 Location: Saint-Maur, France, https...
|
Senior Member Account Moderator |
|
|
Quote: | if anybody, even a developer or DBA, inserts through SQL*Plus instead of a through a procedure, and I have seen this happen too many times, then you have a mess
|
No, as you don't allow this, for instance with a trigger ( ) that checks an environment variable (package/context value, application info...).
Triggers are not for complex logic.
I think as a bad thing when something happens by magic like triggers do. More most of the time triggers are misused and only work in a single user environment.
As I said I didn't analyze what OP wants to do (actually I don't understand it) but anyway seeing your code I can say that:
- what happens if 2 users insert the same record at the same time? Then your "select count" is wrong (functionnaly but not for the database) and you insert twice "lunch detention" (or the like, as I said I don't really understand the process).
And I don't speak about the case when there are concurrent deletes and updates.
Regards
Michel
[Updated on: Sat, 29 March 2008 12:18] Report message to a moderator
|
|
|
Re: After/Before Insert Trigger [message #309910 is a reply to message #309893] |
Sat, 29 March 2008 14:27 |
|
Barbara Boehmer
Messages: 9100 Registered: November 2002 Location: California, USA
|
Senior Member |
|
|
You could use one of Tom Kyte's methods with multiple triggers and package and such and some locking to use the trigger method in a multi-user environment, but I suppose the procedure method would be a lot simpler. If you commit within the procedure, which is something that is usually avoided but you can't have it both ways, then you can force a commit of one row at a time, so you get the count right. So, here is an example of the procedure method.
SCOTT@orcl_11g> CREATE TABLE behaviour
2 (behaviour_id NUMBER,
3 be_stu_id NUMBER,
4 be_class_id NUMBER,
5 date_received DATE)
6 /
Table created.
SCOTT@orcl_11g> CREATE TABLE detention
2 (be_stu_id NUMBER,
3 be_class_id NUMBER,
4 date_received DATE,
5 behaviours NUMBER,
6 punishment VARCHAR2 (25))
7 /
Table created.
SCOTT@orcl_11g> CREATE SEQUENCE behaviour_id_seq
2 /
Sequence created.
SCOTT@orcl_11g> CREATE OR REPLACE PROCEDURE insert_behaviour
2 (p_stu_id IN behaviour.be_stu_id%TYPE,
3 p_class_id IN behaviour.be_class_id%TYPE,
4 p_date IN behaviour.date_received%TYPE)
5 AS
6 v_count NUMBER;
7 BEGIN
8 SELECT COUNT (*) + 1
9 INTO v_count
10 FROM behaviour
11 WHERE be_stu_id = p_stu_id
12 AND be_class_id = p_class_id
13 AND date_received = p_date;
14 IF v_count = 2 THEN
15 DBMS_OUTPUT.PUT_LINE (p_stu_id || ' has ' || v_count || ' behaviours - lunch detention');
16 INSERT INTO detention (be_stu_id, be_class_id, date_received, behaviours, punishment)
17 VALUES (p_stu_id, p_class_id, p_date, v_count, 'lunch detention');
18 ELSIF v_count = 3 THEN
19 DBMS_OUTPUT.PUT_LINE (p_stu_id || ' has ' || v_count || ' behaviours - after school detention');
20 INSERT INTO detention (be_stu_id, be_class_id, date_received, behaviours, punishment)
21 VALUES (p_stu_id, p_class_id, p_date, v_count, 'after school detention');
22 END IF;
23 INSERT INTO behaviour (behaviour_id, be_stu_id, be_class_id, date_received)
24 SELECT behaviour_id_seq.NEXTVAL, p_stu_id, p_class_id, p_date FROM DUAL;
25 COMMIT;
26 END insert_behaviour;
27 /
Procedure created.
SCOTT@orcl_11g> SHOW ERRORS
No errors.
SCOTT@orcl_11g> exec insert_behaviour (1, 2, TRUNC (SYSDATE))
PL/SQL procedure successfully completed.
SCOTT@orcl_11g> exec insert_behaviour (2, 4, TRUNC (SYSDATE))
PL/SQL procedure successfully completed.
SCOTT@orcl_11g> exec insert_behaviour (5, 3, TRUNC (SYSDATE))
PL/SQL procedure successfully completed.
SCOTT@orcl_11g> exec insert_behaviour (5, 3, TRUNC (SYSDATE))
5 has 2 behaviours - lunch detention
PL/SQL procedure successfully completed.
SCOTT@orcl_11g> exec insert_behaviour (1, 2, TRUNC (SYSDATE))
1 has 2 behaviours - lunch detention
PL/SQL procedure successfully completed.
SCOTT@orcl_11g> exec insert_behaviour (5, 3, TRUNC (SYSDATE))
5 has 3 behaviours - after school detention
PL/SQL procedure successfully completed.
SCOTT@orcl_11g> SELECT * FROM behaviour
2 /
BEHAVIOUR_ID BE_STU_ID BE_CLASS_ID DATE_RECE
------------ ---------- ----------- ---------
1 1 2 29-MAR-08
2 2 4 29-MAR-08
3 5 3 29-MAR-08
4 5 3 29-MAR-08
5 1 2 29-MAR-08
6 5 3 29-MAR-08
6 rows selected.
SCOTT@orcl_11g> SELECT * FROM detention
2 /
BE_STU_ID BE_CLASS_ID DATE_RECE BEHAVIOURS PUNISHMENT
---------- ----------- --------- ---------- -------------------------
5 3 29-MAR-08 2 lunch detention
1 2 29-MAR-08 2 lunch detention
5 3 29-MAR-08 3 after school detention
SCOTT@orcl_11g>
|
|
|
|
Re: After/Before Insert Trigger [message #309919 is a reply to message #309910] |
Sat, 29 March 2008 14:58 |
jay565260
Messages: 9 Registered: March 2008
|
Junior Member |
|
|
Thankyou for your assistance i realy appreciate it. With regards to using count is it possible to reset it? so that a student say who gets 6 behaviours in one day would receive a lunch time and an afterschool detention?
Kindest Regards
Jay
|
|
|
Re: After/Before Insert Trigger [message #309920 is a reply to message #309919] |
Sat, 29 March 2008 15:13 |
|
Barbara Boehmer
Messages: 9100 Registered: November 2002 Location: California, USA
|
Senior Member |
|
|
jay565260 wrote on Sat, 29 March 2008 12:58 | Thankyou for your assistance i realy appreciate it. With regards to using count is it possible to reset it? so that a student say who gets 6 behaviours in one day would receive a lunch time and an afterschool detention?
Kindest Regards
Jay
|
I am not sure that I understand the requirement. The way that the procedure that I supplied works is that, after 2 behaviours in the same day, the student gets lunch detention, after a 3rd behaviour on the same day, the student gets detention after school, in addition to the lunch detention. Nothing happens after just 1 behaviour and nothing additional happens after 4 or more behaviours in the same day. If you want it differently, then just change the 2 and 3 to whatever numbers you want and add more routines for additional numbers. However, if you intended for the after school detention after the 3rd behaviour to be instead of the lunch detention after the second behaiour, then you will need to add some extra code to delete the lunch detention from the detention table.
If you still need help, then please provide more explanation and a copy and paste of what you tried and the results.
|
|
|
Goto Forum:
Current Time: Mon Dec 09 19:59:43 CST 2024
|