After insert trigger update - sql

CREATE TABLE "EMPLOYEE_BP"
( "EMP_ID" VARCHAR2(10) NOT NULL ENABLE,
"FNAME" VARCHAR2(20),
"LNAME" VARCHAR2(20),
"JOB_ROLE" VARCHAR2(20),
"AIRPORT_CODE" VARCHAR2(10) NOT NULL ENABLE,
"SALARY" NUMBER(9,0),
"MOBILE" NUMBER(10,0)
);
CREATE or REPLACE TRIGGER emp_after_insert AFTER INSERT ON EMPLOYEE
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO EMPLOYEE_BP values (:NEW.EMP_ID, :NEW.FNAME, :NEW.LNAME, :NEW.JOB_ROLE, : NEW.AIRPORT_CODE, : NEW.SALARY, : NEW.MOBILE);
DBMS_OUTPUT.PUT_LINE('Record successfully inserted into emp_backup table');
END;
--> Apparently constraints are not inserted into backup tables
​The table gets created, but it gives me an error for the trigger on line 4,where the begin statement is. Ther error is error at line 4 statement ignored. The synthax seems ok and I'm confident it's a small error but I can't figure it out. I am using Oracle.
Thanks in advance.

Running the trigger as you have it, I actually get an internal Oracle error, which is not good. But I think the problem is with the spaces you have between the : and the NEW.
This works for me:
SQL> CREATE or REPLACE TRIGGER emp_after_insert AFTER INSERT ON EMPLOYEE
2 FOR EACH ROW
3 DECLARE
4 BEGIN
5 INSERT INTO EMPLOYEE_BP values (:NEW.EMP_ID, :NEW.FNAME, :NEW.LNAME, :NEW.JOB_ROLE, :NEW.AIRPORT_CODE, :NEW.SALARY, :NEW.MOBILE);
6 DBMS_OUTPUT.PUT_LINE('Record successfully inserted into emp_backup table');
7 END;
8 /
Trigger created.

I'm not an Oracle expert but you would either need to strike your DECLARE line or actually declare something based on this example
CREATE or REPLACE TRIGGER emp_after_insert AFTER INSERT ON EMPLOYEE
FOR EACH ROW
DECLARE
unused varchar2(10);
BEGIN
INSERT INTO EMPLOYEE_BP values (:NEW.EMP_ID, :NEW.FNAME, :NEW.LNAME, :NEW.JOB_ROLE, :NEW.AIRPORT_CODE, :NEW.SALARY, :NEW.MOBILE);
DBMS_OUTPUT.PUT_LINE('Record successfully inserted into emp_backup table');
END;

Related

Create a Trigger with merge to monitor tables

I need to create a Trigger to monitor this table :
CREATE TABLE "REFERENCE"
( "NUM_CONTRACT" VARCHAR2(20 CHAR),
"NATURE" VARCHAR2(20 CHAR),
"PR" VARCHAR2(14 CHAR),
)
I just want to store the date of the last modification and his "PR" in this table :
CREATE TABLE EVENT_REFERENCE (
ID NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1) NOT NULL,
reference VARCHAR(14) NOT NULL UNIQUE,
date_modification TIMESTAMP(6),
PRIMARY KEY (ID)
)
I use a merge in order to avoid to have duplicate rows with the same reference and different date . I just want to keep the date of last modification for each reference rows
For that i created this trigger but idk what's wrong with it . Can anyone help me ?
CREATE OR REPLACE TRIGGER TRG_REFERENCE
AFTER INSERT OR UPDATE ON REFERENCE
FOR EACH ROW
DECLARE
PRAGMA autonomous_transaction;
BEGIN
IF INSERTING
THEN
MERGE INTO EVENT_REFERENCE hist
USING (select :new.pr
from dual) t1
ON (t1.pr=hist.reference)
WHEN MATCHED THEN
UPDATE SET hist.date_modification=systimestamp
WHEN NOT MATCHED THEN
INSERT INTO EVENT_REFERENCE (REFERENCE, DATE_MODIFICATION)
VALUES (:NEW.prm, systimestamp);
END IF;
COMMIT;
END;
You have:
:NEW.prm when it should be :NEW.pr
INSERT INTO EVENT_REFERENCE (REFERENCE, DATE_MODIFICATION) when you just need INSERT (REFERENCE, DATE_MODIFICATION)
You also use AFTER INSERT OR UPDATE and then check IF INSERTING why not just use AFTER INSERT?
The fixed code:
CREATE OR REPLACE TRIGGER TRG_REFERENCE
AFTER INSERT OR UPDATE ON REFERENCE
FOR EACH ROW
DECLARE
PRAGMA autonomous_transaction;
BEGIN
IF INSERTING
THEN
MERGE INTO EVENT_REFERENCE hist
USING DUAL t1
ON (:new.pr=hist.reference)
WHEN MATCHED THEN
UPDATE SET hist.date_modification=systimestamp
WHEN NOT MATCHED THEN
INSERT (REFERENCE, DATE_MODIFICATION)
VALUES (:NEW.pr, systimestamp);
END IF;
COMMIT;
END;
/
db<>fiddle here

Enabling and disabling a trigger inside another trigger

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.

How to create a trigger on a table that for each inserted row populates id with value from sequence in pl/sql?

create or replace TRIGGER dept_id_trig
BEFORE INSERT ON DEPARTMENTS
FOR EACH ROW
DECLARE
BEGIN
IF(:NEW.DEPARTMENT_ID IS NULL )
THEN
select DEPT_DEPTID_SEQ.nextval INTO :new.DEPARTMENT_ID FROM dual;
END IF;
END;
Please check below trigger.
CREATE OR REPLACE TRIGGER dept_id_trig
BEFORE INSERT ON DEPARTMENTS
FOR EACH ROW
DECLARE
BEGIN
:new.DEPARTMENT_ID := DEPT_DEPTID_SEQ.nextval;
END;
If you are on Oracle 12c or later, use an IDENTITY clause on the column rather than a trigger:
CREATE TABLE departments(
department_id NUMBER(10,0)
GENERATED ALWAYS AS IDENTITY
CONSTRAINTS departments__department_id__pk PRIMARY KEY
)
This is a trigger generated from Oracle itself when creating a new table:
create or replace TRIGGER dept_id_trig
BEFORE INSERT ON DEPARTMENTS
FOR EACH ROW
BEGIN
<<COLUMN_SEQUENCES>>
BEGIN
IF INSERTING AND :NEW.DEPARTMENT_ID IS NULL THEN
SELECT DEPT_DEPTID_SEQ.NEXTVAL INTO :NEW.DEPARTMENT_ID FROM SYS.DUAL;
END IF;
END COLUMN_SEQUENCES;
END;

How to avoid mutating table in a trigger when working with nested table, and do an update into another table?

I have a code that uses a trigger to do an update into a table after a dml insert has been done, but i need the information inside an atributte that is a nested table, and with that information do the update, but my code throws a mutating table error, and i want to know what is it that i am doing wrong, this is the code with the tables, types and trigger involved.
----create the type tipo_detalle---------------
CREATE OR REPLACE TYPE tipo_detalle AS OBJECT(
codigo NUMBER(1),
cantidad NUMBER(2)
);
/
-----declare the nested table with type tipo_detalle---
CREATE OR REPLACE TYPE detalle_anidado AS TABLE OF tipo_detalle;
/
---------create the table pedido------------------------
CREATE TABLE pedido(
cod_bodega REFERENCES bodega,
dia NUMBER(8),
columna_detalle detalle_anidado,
PRIMARY KEY(cod_bodega,dia)
)
NESTED TABLE columna_detalle STORE AS columna_detalle_anidada
((PRIMARY KEY(NESTED_TABLE_ID,codigo)));
---table where i am going to insert after insert in pedido----
CREATE TABLE inventario(
cod_bodega REFERENCES bodega,
cod_producto REFERENCES producto,
existencia NUMBER(8),
PRIMARY KEY(cod_bodega,cod_producto)
);
------ trigger to do an insert into inventario-----------
CREATE OR REPLACE TRIGGER triggers_de_pedido
FOR INSERT OR UPDATE OR DELETE ON pedido
COMPOUND TRIGGER
contador NUMBER(8);
fila pedido.columna_detalle%TYPE;
cod_producto_ NUMBER(1);
cantidad_ NUMBER(2);
indice NUMBER(4);
AFTER EACH ROW IS
BEGIN
IF INSERTING THEN
SELECT columna_detalle INTO fila FROM pedido WHERE
cod_bodega=:NEW.cod_bodega AND dia=:NEW.dia;
indice:=fila.FIRST;
WHILE indice IS NOT NULL LOOP
cod_producto_:=fila(indice).codigo;
cantidad_:=fila(indice).cantidad;
UPDATE inventario SET existencia=existencia-cantidad_
WHERE cod_bodega=:NEW.cod_bodega AND cod_producto=cod_producto_;
indice:=fila.NEXT(indice);
END LOOP;
END IF;
END AFTER EACH ROW;
END triggers_de_pedido;
/
The error is raised because you are selecting from the Trigger owner(the table pedido) inside the Trigger.
Change this select statement
SELECT columna_detalle INTO fila FROM pedido WHERE ...
to
IF INSERTING THEN
fila := :NEW.columna_detalle;

Oracle SQL error "ORA-00984: column not allowed here" when trying to replace a column

This question is not a duplicate from this one because even if the error messages are equal the answers there do not apply to my case.
I need to change a previous PK Id column defined as VARCHAR(36) NOT NULL to an incremental integer value. I'm trying to write a script to do this but when I run the alter table statement it fails with the error on the title.
The table is previously defined as:
CREATE TABLE journal_messages(
ID VARCHAR(36) NOT NULL, -- column to be changed
MESSAGE VARCHAR(2048) NOT NULL,
MESSAGE_TYPE VARCHAR(30) NOT NULL,
MSG_DATE TIMESTAMP NOT NULL,
MODULE_CODE INTEGER NOT NULL
);
ALTER TABLE journal_messages ADD (CONSTRAINT journal_messages_pk PRIMARY KEY (ID));
The script I'm running is:
DELETE FROM JOURNAL_MESSAGES;
ALTER TABLE JOURNAL_MESSAGES DROP COLUMN ID;
CREATE SEQUENCE journal_messages_seq START WITH 1;
ALTER TABLE JOURNAL_MESSAGES ADD (ID NUMBER(10) DEFAULT journal_messages_seq.nextval NOT NULL); -- error happens here
ALTER TABLE journal_messages ADD (
CONSTRAINT journal_messages_pk PRIMARY KEY (ID));
When I try to create a trigger it to update the incremental, it fails with SQL Error [4098] [42000]: ORA-04098: trigger 'TRG_SEQ_JOURNAL_MSG' is invalid and failed re-validation when I try to insert a new tuple:
ALTER TABLE JOURNAL_MESSAGES DROP COLUMN ID;
ALTER TABLE JOURNAL_MESSAGES ADD (ID NUMBER(10) NOT NULL);
create or replace trigger trg_seq_journal_msg
before insert on journal_messages
for each row
begin
:new.id := journal_messages_seq.nextval;
end;
/
INSERT INTO JOURNAL_MESSAGES (message, MESSAGE_TYPE, msg_date, MODULE_CODE) VALUES ('test', 'alteration', CURRENT_TIMESTAMP, '10');
Umm ... not like that, but like this:
once the table is empty, you don't have to drop the column - just modify its datatype
use a trigger to automatically set IDs value
If you were on 12c, you could have used identity column.
SQL> CREATE TABLE journal_messages(
2 ID VARCHAR(36) NOT NULL, -- column to be changed
3 MESSAGE VARCHAR(2048) NOT NULL,
4 MESSAGE_TYPE VARCHAR(30) NOT NULL,
5 MSG_DATE TIMESTAMP NOT NULL,
6 MODULE_CODE INTEGER NOT NULL
7 );
Table created.
SQL> delete from journal_Messages;
0 rows deleted.
SQL> alter table journal_messages modify (id number(10));
Table altered.
SQL> CREATE SEQUENCE journal_messages_seq START WITH 1;
Sequence created.
SQL> create or replace trigger trg_bi_joumes
2 before insert on journal_messages
3 for each row
4 begin
5 :new.id := journal_messages_seq.nextval;
6 end;
7 /
Trigger created.
SQL>
[EDIT: after reading your comment and saw your edition]
That still works OK - I literally copy/pasted your code and got this:
SQL> ALTER TABLE JOURNAL_MESSAGES DROP COLUMN ID;
Table altered.
SQL> ALTER TABLE JOURNAL_MESSAGES ADD (ID NUMBER(10) NOT NULL);
Table altered.
SQL> create or replace trigger trg_seq_journal_msg
2 before insert on journal_messages
3 for each row
4 begin
5 :new.id := journal_messages_seq.nextval;
6 end;
7 /
Trigger created.
SQL> INSERT INTO JOURNAL_MESSAGES (message, MESSAGE_TYPE, msg_date, MODULE_CODE) VALUES ('test', 'alteration', CURRENT_TIMESTAMP, '10')
2 ;
1 row created.
SQL>
As you can see, everything seems to be just fine. Try the following: recompile the trigger and show errors (if any; if so, please, post them here):
SQL> alter trigger trg_seq_journal_msg compile;
Trigger altered.
SQL> show err
No errors.
SQL>