Trigger errors ORA-04092 ORA-04088 - sql

I created a trigger as below:
CREATE OR REPLACE TRIGGER trigger_test
AFTER INSERT ON trigger_1
FOR EACH ROW
DECLARE
t_identifier VARCHAR2(10);
t_name VARCHAR2(20);
BEGIN
t_identifier := (:NEW.IDENTIFIER);
t_name := (:NEW.NAME);
INSERT INTO trigger_2(IDENTIFIER,NAME)VALUES(t_identifier,t_name);
COMMIT;
END;
I am trying to insert a row in trigger_1
INSERT INTO trigger_1(IDENTIFIER,NAME)
VALUES('1234567','Vijay');
It is giving me the errors:
ORA-04092: cannot COMMIT in a trigger
ORA-06512: at "LVSDBO46.TRIGGER_TEST", line 8
ORA-04088: error during execution of trigger 'LVSDBO46.TRIGGER_TEST'
Could nybody please help?

Just remove
COMMIT;
from the trigger code. Trigger execute in an ongoing transaction, so you cannot do a separate commit. When the transaction is commited, your insert in trigger_2 will also be commited.

Might I suggest shortening it a bit.
CREATE OR REPLACE TRIGGER trigger_test
AFTER INSERT ON trigger_1
FOR EACH ROW
BEGIN
INSERT INTO trigger_2 (IDENTIFIER,NAME) VALUES (:NEW.IDENTIFIER,:NEW.NAME);
END;

In case you really really need to commit (chances are you don't have to, but just in case...) you can create a procedure with the AUTONOMOUS_TRANSACTION PRAGMA.

Related

How to insert data into table even if trigger fails?

Oracle 11.1
I have custom logging table where I insert data:
CREATE TABLE log_table
(
message VARCHAR2(255),
created_by VARCHAR2(40) NOT NULL,
created_at DATE NOT NULL,
);
I have a trigger that runs on a specific table which does some checkings. My problem is: when the trigger fails, I want to be able to log some data into the log_table.
Trigger:
CREATE OR REPLACE TRIGGER my_trigger
FOR INSERT OR UPDATE OF column
ON my_table
COMPOUND TRIGGER
BEFORE STATEMENT IS
BEGIN
// code
END BEFORE STATEMENT;
BEFORE EACH ROW IS
BEGIN
IF (/*condition for failing*/) THEN
EXECUTE IMMEDIATE 'INSERT INTO mesaj_ama VALUES (:my_message, :my_user, :my_data)'
USING 'custom error message', SYS.LOGIN_USER, SYSDATE;
RAISE_APPLICATION_ERROR(-20001, 'some error');
END IF;
END BEFORE EACH ROW;
END my_trigger;
/
The following code doesn't work. I tried to use EXECUTE IMMEDIATE maybe to force it, but didn't work. I know that in case of an error, there is automatically a table rollback (which means that the INSERT command is cancelled), but I need a way to do this. Any help?
The concept you're looking for is an Autonomous Trasnaction, eg
CREATE OR REPLACE TRIGGER log_sal
BEFORE UPDATE OF salary ON emp FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO log (
log_id,
up_date,
new_sal,
old_sal
)
VALUES (
:old.employee_id,
SYSDATE,
:new.salary,
:old.salary
);
COMMIT;
END;
Yes, PRAGMA AUTONOMOUS_TRANSACTION seems to be the answer. Here is the working code:
Defined a procedure for logging:
CREATE OR REPLACE PROCEDURE log_error(p_error log_table.message % TYPE) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO log_table
VALUES (p_error, SYS.LOGIN_USER, SYSDATE);
COMMIT;
END;
and the trigger which calls the procedure:
CREATE OR REPLACE TRIGGER my_trigger
FOR INSERT OR UPDATE OF column
ON my_table
COMPOUND TRIGGER
BEFORE STATEMENT IS
BEGIN
// code
END BEFORE STATEMENT;
BEFORE EACH ROW IS
BEGIN
IF (/*condition for failing*/) THEN
log_error('custom error message');
RAISE_APPLICATION_ERROR(-20001, 'custom error message');
END IF;
END BEFORE EACH ROW;
END my_trigger;
/

Is this DML or DDL trigger?

I wanted to ask if this is a DML or DDL Trigger ?
CREATE OR REPLACE TRIGGER INFORMATION_TIMEZONE
BEFORE INSERT ON information
FOR EACH ROW
BEGIN
IF (session_params.getCurrentRefperso) IS NOT NULL THEN
:new.DT_HOUR_TIME_ZONE := current_timestamp();
END IF;
END;
The BEFORE INSERT defines this trigger to be fired when an INSERT is done.
As INSERT is a DML statement, the trigger is a DML trigger.
A DDL trigger would e.g. have BEFORE CREATE or BEFORE DROP in the trigger definition.

how to use trigger in sql

CREATE TABLE table_001(
Day_date date
);
CREATE TABLE table_002(
new_Day_date date
);
CREATE OR REPLACE TRIGGERS trigger
AFTER INSERT ON table_001
FOR EACH ROW
BEGIN
INSERT INTO table_002 VALUES(SYSDATE)
END;
You have a few syntax errors. It's not "TRIGGERS". Also, give a valid trigger name. A semicolon was missing after the insert.
CREATE OR REPLACE TRIGGER trigger_name
AFTER INSERT ON table_001
FOR EACH ROW
BEGIN
INSERT INTO table_002(new_Day_date) VALUES(SYSDATE);
END;
/
CREATE OR REPLACE TRIGGER trigger_name
AFTER INSERT ON table_001
FOR EACH ROW
BEGIN
INSERT INTO table_002 VALUES(SYSDATE);
END;

Unable to call a stored procedure from the trigger

CREATE OR REPLACE PROCEDURE UPDATE_AGE_VALUES
IS
cursor_ssn_number tbl_Patient.ssn_number%type;
cursor_patient_age tbl_Patient.patient_age%type;
age1 tbl_Patient.patient_age%type;
age2 tbl_Patient.patient_age%type;
age3 tbl_Patient.patient_age%type;
ssn_number1 tbl_Patient.ssn_number%type;
ssn_number2 tbl_Patient.ssn_number%type;
ssn_number3 tbl_Patient.ssn_number%type;
average number:=0;
i number:=1;
CURSOR cursor_tbl_Patient IS
SELECT ssn_number,patient_age FROM tbl_Patient ORDER BY patient_age ASC;
BEGIN
OPEN cursor_tbl_Patient;
LOOP
FETCH cursor_tbl_Patient into cursor_ssn_number,cursor_patient_age;
EXIT WHEN cursor_tbl_Patient%NOTFOUND;
IF i=1 THEN
age1:=cursor_patient_age;
ssn_number1:=cursor_ssn_number;
i:=i+1;
ELSIF i=2 THEN
age2:=cursor_patient_age;
ssn_number2:=cursor_ssn_number;
i:=i+1;
ELSIF i=3 THEN
age3:=cursor_patient_age;
ssn_number3:=cursor_ssn_number;
average:=(age1+age2+age3)/3;
UPDATE tbl_Patient SET patient_age=average where ssn_number IN (ssn_number1,ssn_number2,ssn_number3);
i:=1;
average:=0;
commit;
END IF;
END LOOP;
CLOSE cursor_tbl_Patient;
END;
/
CREATE OR REPLACE TRIGGER CHANGE_ROW_VALUES
AFTER INSERT ON tbl_Patient
FOR EACH ROW
BEGIN
CALL UPDATE_AGE_VALUES;
END;
/
Above code tries to modify the row values after a row is inserted. The procedure is created a execute.But I'm not able to call the procedure from the Trigger. I don't know why.
The error I'm getting is :
2/7 ,PLS-00103: Encountered the symbol "UPDATE_AGE_VALUES" when
,expecting one of the following:
,:= . ( # % ;
,The symbol ":=" was substituted for "UPDATE_AGE_VALUES" to
,continue.
Am I missing out anything?
Thanks in advance!!!
CALL is not a valid statement in PL/SQL. To call a procedure in PL/SQL you just need to give its name, as in:
CREATE OR REPLACE TRIGGER CHANGE_ROW_VALUES
AFTER INSERT ON tbl_Patient
FOR EACH ROW
BEGIN
UPDATE_AGE_VALUES;
END;
Your next problem will be that the UPDATE_AGE_VALUES reads and updates tbl_Patient, which will fail because UPDATE_AGE_VALUES is called from a row trigger which is defined on tbl_Patient. If you remove the FOR EACH ROW from the trigger it might work, but I won't answer for the performance.
Share and enjoy.
CREATE OR REPLACE TRIGGER CHANGE_ROW_VALUES
AFTER INSERT ON tbl_Patient
FOR EACH ROW
BEGIN
UPDATE_AGE_VALUES();
END;
This worked for me!!!

Ora-04072: INVALID TRIGGER TYPE

I'm trying to execute the following SQL statement on Oracle 11g. I'm not experienced when it comes to Oracle and I'm not sure why this is failing. This query was provided to me by our developer.
I was attempting to execute this through the SQL worksheet in OEM.
CREATE OR REPLACE TRIGGER TBL_ADMINCOMMAND_TRG BEFORE
INSERT OR UPDATE ON tbl_AdminCommands FOR EACH ROW
BEGIN
IF inserting
AND :new.ADMINCOMMANDID IS NULL THEN
SELECT TBL_ADMINCOMMANDS_SEQ.nextval INTO :new.ADMINCOMMANDID FROM DUAL;
END IF;
END;
ALTER TRIGGER TBL_ADMINCOMMAND_TRG ENABLE;
The code you show works for me, but only as two separate commands:
1)
CREATE OR REPLACE TRIGGER TBL_ADMINCOMMAND_TRG BEFORE
INSERT OR UPDATE ON tbl_AdminCommands FOR EACH ROW
BEGIN
IF inserting
AND :new.ADMINCOMMANDID IS NULL THEN
SELECT TBL_ADMINCOMMANDS_SEQ.nextval INTO :new.ADMINCOMMANDID FROM DUAL;
END IF;
END;
2)
ALTER TRIGGER TBL_ADMINCOMMAND_TRG ENABLE;
Try doing them one at a time.
As an aside, this line:
SELECT TBL_ADMINCOMMANDS_SEQ.nextval INTO :new.ADMINCOMMANDID FROM DUAL;
can be simplified to this in 11G:
:new.ADMINCOMMANDID := TBL_ADMINCOMMANDS_SEQ.nextval;
In fact, the whole trigger can be simplified to:
CREATE OR REPLACE TRIGGER TBL_ADMINCOMMAND_TRG
BEFORE INSERT ON tbl_AdminCommands
FOR EACH ROW
WHEN (NEW.ADMINCOMMANDID IS NULL)
BEGIN
:new.ADMINCOMMANDID := TBL_ADMINCOMMANDS_SEQ.nextval;
END;
If you are using SQL*Plus, you should end your PL/SQL commands with a single forward slash on a line by itself:
CREATE OR REPLACE TRIGGER TBL_ADMINCOMMAND_TRG
BEFORE INSERT OR UPDATE ON tbl_AdminCommands
FOR EACH ROW
BEGIN
IF inserting AND :new.ADMINCOMMANDID IS NULL
THEN
SELECT TBL_ADMINCOMMANDS_SEQ.nextval
INTO :new.ADMINCOMMANDID
FROM DUAL;
END IF;
END;
/
ALTER TRIGGER TBL_ADMINCOMMAND_TRG ENABLE;
Also note that if your trigger uses IF inserting you could do only a trigger BEFORE INSERT.