I got a table Location
CREATE TABLE Location (
idL INTEGER,
City VARCHAR2(15) NOT NULL,
Street VARCHAR2(35) NOT NULL,
Nation CHAR(6) NOT NULL,
CONSTRAINT PK_idL PRIMARY KEY(idL)
);
And a table Person
CREATE TABLE Person(
p_Name VARCHAR2(20) NOT NULL,
p_Surname VARCHAR2(20) NOT NULL,
idP INTEGER,
b_Date DATE NOT NULL,
id_PL INTEGER,
CONSTRAINT PK_idP PRIMARY KEY(idP),
CONSTRAINT FK_idPL FOREIGN KEY(id_PL) REFERENCES Location(idL)
);
I calculate the primary key "automatically" as it follows:
CREATE SEQUENCE seq_loc_pk
start with 1
increment by 1;
CREATE OR REPLACE TRIGGER auto_pk_loc
BEFORE INSERT ON Location
FOR EACH ROW
BEGIN
:new.idL := seq_loc_pk.nextval;
END;
/
Now I want to insert the residence for a new person (after I've created the right view of course) with an instead of trigger like this:
CREATE OR REPLACE TRIGGER newperson
INSTEAD OF INSERT ON Residence
FOR EACH ROW
DECLARE
nl Loc.idL%TYPE;
BEGIN
ALTER TRIGGER auto_pk_loc DISABLE; -- Error
nl := seq_loc_pk.nextval;
:NEW.idL := nl;
INSERT INTO Location VALUES(:NEW.City,:NEW.Street,:NEW.Nation);
INSERT INTO Patient VALUES(:NEW.P_Name,:NEW.P_Surname,:NEW.B_Date,,nl);
ALTER TRIGGER auto_pk_loc ENABLE;
END;
/
I thought about disabling and enabling the trigger auto_pk_loc so that it doesn't create extra values for no reason, but I think this is not the right way to do it? What is it though? Thanks for whoever answers.
You can do this by placing it in execute immedaite
:
BEGIN
execute immedidate 'ALTER TRIGGER auto_pk_loc DISABLE';
nl := seq_loc_pk.nextval;
:NEW.idL := nl;
INSERT INTO Location VALUES(:NEW.City,:NEW.Street,:NEW.Nation);
INSERT INTO Patient VALUES(:NEW.P_Name,:NEW.P_Surname,:NEW.B_Date,,nl);
execute immedidate 'ALTER TRIGGER auto_pk_loc ENABLE';
END;
/
But this will cause you all sorts of issues; DDL commits so you'll have to make this an autonomous transaction and you'll hit concurrency problems. This is best avoided.
A better method is to use the returning
clause to fetch the value you just inserted:
BEGIN
INSERT INTO Location VALUES(:NEW.City,:NEW.Street,:NEW.Nation)
returning idl into nl;
INSERT INTO Patient VALUES(:NEW.P_Name,:NEW.P_Surname,:NEW.B_Date,nl);
END;
/
Though as @astentx noted, you probably want to use merge
to avoid having duplicate locations. This doesn't support returing
, so you'll have to use some combination of insert+update instead.
Finally - assuming you're on 12c or higher - it's better to use an identity column or sequence default to auto-generate the location IDs over a trigger.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.