Reputation: 3
I would like to create primary key without using sequence but I don't mind using trigger. I am using oracle 11gR2. my script contains the following. a. create table (dept2) b. insert sample data c. create trigger (find max value, add 1, insert) d. insert another record (trigger should fire) it gives the above error. below is my script.
drop table dept2 ;
create table dept2
(
deptno number(2),
dname varchar2(20),
mgr number(3)
) ;
insert into dept2 values (11, 'a', 23) ;
insert into dept2 values (12, 'b', 24) ;
select * from dept2 ;
CREATE OR REPLACE TRIGGER trig_deptno2
BEFORE INSERT ON dept2
FOR EACH ROW
DECLARE v_deptno NUMBER(2) ;
BEGIN
SELECT MAX(deptno) INTO v_deptno
FROM dept2 ;
INSERT INTO dept2 VALUES
((v_deptno + 1), :NEW.dname, :NEW.mgr) ;
END trig_deptno2 ;
/
SHOW ERR
L
insert into dept2 (dname, mgr) values ('d', 24) ;
select * from dept2 ;
L
Can anyone tell me where is the mistake or how I can correct the error?
Upvotes: 1
Views: 11550
Reputation: 311796
Your trigger fires when inserting to dept2
, and then performs an insert
on dept2
, which causes the trigger to re-fire, etc. in an endless recursion.
You should not call insert
explicitly - just update the :NEW
record, and once the trigger is completed, that updated record will be inserted into the table:
CREATE OR REPLACE TRIGGER trig_deptno2
BEFORE INSERT ON dept2
FOR EACH ROW
DECLARE v_deptno NUMBER(2) ;
BEGIN
SELECT MAX(deptno) + 1 INTO :NEW.deptno
FROM dept2;
END trig_deptno2 ;
/
Upvotes: 2
Reputation: 262684
Why do you want to do that?
If you need auto-generated sequence numbers, use a sequence.
Two main problems with SELECT MAX(id) + 1
:
It does not work with concurrent transactions
It repeats numbers when you delete the current "max"
Upvotes: 4
Reputation: 1270361
You are doing a "before insert" trigger. In such a trigger, you don't insert into the same table -- otherwise, you can get an infinite loop. Just assign to the variable value:
CREATE OR REPLACE TRIGGER trig_deptno2
BEFORE INSERT ON dept2
FOR EACH ROW
DECLARE v_deptno NUMBER(2) ;
BEGIN
SELECT coalesce(MAX(deptno) + 1, 1) INTO :new.deptno
FROM dept2 ;
END trig_deptno2 ;
When the trigger is finished, it will insert the right values from the new
variable.
Let me just say that sequences exist for a reason, and you should use them for this purpose. Trying to mimic their functionality is likely to lead to errors.
Upvotes: 4