I am trying to create a simple trigger in an oracle 10g database. This script to Create the trigger runs clean.
CREATE OR REPLACE TRIGGER newAlert
AFTER INSERT OR UPDATE ON Alerts
BEGIN
INSERT INTO Users (userID, firstName, lastName, password) VALUES ('how', 'im', 'testing', 'this trigger')
END;
/
But when I run:
INSERT INTO Alerts(observationID, dateSent, message, dateViewed) VALUES (3, CURRENT_TIMESTAMP, 'Alert: You have exceeded the Max Threshold', NULL);
to activate the trigger, I get this error message:
ORA-04098: trigger 'JMD.NEWALERT' is invalid and failed re-validation
(0 rows affected)
I don't understand whats causes this error. Do you know what causes this error? Or why this is happening?
Thank you in advance!
-David
Oracle will try to recompile invalid objects as they are referred to. Here the trigger is invalid, and every time you try to insert a row it will try to recompile the trigger, and fail, which leads to the ORA-04098 error.
You can select * from user_errors where type = 'TRIGGER' and name = 'NEWALERT' to see what error(s) the trigger actually gets and why it won't compile. In this case it appears you're missing a semicolon at the end of the insert line:
INSERT INTO Users (userID, firstName, lastName, password)
VALUES ('how', 'im', 'testing', 'this trigger')
So make it:
CREATE OR REPLACE TRIGGER newAlert
AFTER INSERT OR UPDATE ON Alerts
BEGIN
INSERT INTO Users (userID, firstName, lastName, password)
VALUES ('how', 'im', 'testing', 'this trigger');
END;
/
If you get a compilation warning when you do that you can do show errors if you're in SQL*Plus or SQL Developer, or query user_errors again.
Of course, this assumes your Users tables does have those column names, and they are all varchar2... but presumably you'll be doing something more interesting with the trigger really.
Cause: A trigger was attempted to be retrieved for execution and was found to be invalid. This also means that compilation/authorization failed for the trigger.
Action: Options are to resolve the compilation/authorization errors, disable the trigger, or drop the trigger.
Syntax
ALTER TRIGGER trigger_Name DISABLE;
ALTER TRIGGER trigger_Name ENABLE;
in my case, this error is raised due to sequence was not created..
CREATE SEQUENCE J.SOME_SEQ MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE ;
Related
IF I create this trigger, then the error is raised when drop or truncate is used on tables, but there is nothing inserted into logTable, but if I delete RAISE_APPLICATION_ERROR... then the values are inserted into logTable, but the drop/truncate are executed too. Why? How can I avoid drop/truncate on Schema (If I use instead of trigger, it is fired only if owner of the schema is dropping/truncating something).
CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
IF ora_dict_obj_owner = 'MySchema' THEN
select user INTO username from dual;
INSERT INTO logTable VALUES(username , SYSDATE);
RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
END IF;
END;
According to the documentation:
Statement-Level Atomicity
Oracle Database supports statement-level atomicity, which means that a SQL statement is an atomic unit of work
and either completely succeeds or completely fails.
A successful statement is different from a committed transaction. A
single SQL statement executes successfully if the database parses and
runs it without error as an atomic unit, as when all rows are changed
in a multirow update.
If a SQL statement causes an error during execution, then it is not
successful and so all effects of the statement are rolled back. This
operation is a statement-level rollback.
The procedure is a PL/SQL statement, it is atomic, if you raise an error within the procedure, then the whole procedure fails and Oracle performs a rollback of all the changes done by this procedure.
But you can create a procedure with AUTONOMOUS_TRANSACTION Pragma in order to bypass this behaviour, in this way:
CREATE TABLE logtable(
username varchar2(200),
log_date date
);
CREATE OR REPLACE PROCEDURE log_message( username varchar2 ) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO logtable( username, log_date ) VALUES ( username, sysdate );
COMMIT;
END;
/
CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
IF ora_dict_obj_owner = 'TEST' THEN
log_message( user );
RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
END IF;
END;
And now:
drop table table1;
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: ERROR, YOU CAN NOT DELETE THIS!!
ORA-06512: at line 6
00604. 00000 - "error occurred at recursive SQL level %s"
*Cause: An error occurred while processing a recursive SQL statement
(a statement applying to internal dictionary tables).
*Action: If the situation described in the next error on the stack
can be corrected, do so; otherwise contact Oracle Support.
select * from logtable;
USERNAME LOG_DATE
-------- -------------------
TEST 2018-04-27 00:16:34
I get the following error when I try to create this trigger in SQLite
create trigger timeslot_check1 after insert on section
for each row
when(new.time_slot_id not in(select time_slot_id
from time_slot))
begin
rollback
end;
ERROR : near "rollback": syntax error:
As shown in the documentation, the only SQL commands allowed in a trigger body are UPDATE, INSERT, DELETE, and SELECT.
To raise an error, you must use the RAISE() function from inside a query:
CREATE TRIGGER timeslot_check1
BEFORE INSERT ON section
FOR EACH ROW
WHEN NEW.time_slot_id NOT IN (SELECT time_slot_id FROM time_slot)
BEGIN
SELECT RAISE(FAIL, "invalid timeslot");
END;
Anyway, this check can be done much easier with a foreign key.
I've created a trigger which should fire everey time I update the firstName of a worker in my table:
CREATE OR REPLACE TRIGGER trigger_before_update
BEFORE UPDATE ON t_workers
FOR EACH ROW
BEGIN
insert into t_logtable
values (pk_workerid , sysdate, :old.firstName)
END;
But every time I try to update a row, this is the error I got:
ora-04098 trigger is invalid and failed re-validation
What is wrong with the trigger?
And as you can see, the point would be to insert old values before update, isn't there any oracle solution, for an universial variable/column name? I mean not :old.firstName, but something, that would check any column, and gets any old value, that has been updated. It could be firstName, lastName, salary anything.
try this:
CREATE OR REPLACE TRIGGER trigger_before_update
BEFORE UPDATE ON t_workers
FOR EACH ROW
BEGIN
insert into t_logtable
values (pk_workerid , sysdate, :old.firstName);
END;
add ; after insert code
I'm creating a trigger within my database, I came across two error that I am not able to fix, I'm pretty sure that those two are relating to my use of DBMS_OUTPUT.PUT_LINE, the rest of the statement does not cause any errors, although it had before.
Errors:
Error(5,3): PL/SQL: SQL Statement ignored
Error(5,15): PL/SQL: ORA-00903: invalid table name
Code:
CREATE TRIGGER INVOICES
BEFORE INSERT OR UPDATE ON BRUINVOICE
FOR EACH ROW
BEGIN
IF :new.BRU_DATE < :new.BRU_PAID_DATE THEN
DBMS_OUTPUT.PUT_LINE('You cannot do that');
ELSE
INSERT INTO table BRUINVOICE
values
from inserted;
END IF;
END;
Check constraints are a better choice (performance-wise) than triggers when it comes to record level validation:
ALTER TABLE bruinvoice
ADD CONSTRAINT validate_bru_date CHECK (BRU_DATE < BRU_PAID_DATE);
Inserting invalid data will raise an error message like the following:
scott#ORCL> insert into bruinvoice values ('21-DEC-14','20-DEC-14');
insert into bruinvoice values ('21-DEC-14','20-DEC-14')
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.VALIDATE_BRU_DATE) violated
I fully agree with cstotzer, a check constraint is much better in your situation at should be the preferred way of doing it. However, just for information this would be the trigger syntax:
CREATE TRIGGER INVOICES
BEFORE INSERT OR UPDATE ON BRUINVOICE
FOR EACH ROW
BEGIN
IF :new.BRU_DATE < :new.BRU_PAID_DATE THEN
RAISE_APPLICATION_ERROR(-20001, 'You cannot do that');
END IF;
END;
You don't need any ELSE, your INSERT or UPDATE will be simply executed in this case.
create or replace trigger "STUDENT_PERSONAL_DETAIL_T1"
AFTER insert or update or delete on "STUDENT_PERSONAL_DETAIL"
for each row
begin
insert into fa1 (s_id,name,class,sec)
select reg_no,name,class,sec
from inserted
end;
This is the trigger created using Oracle xe trigger creating interface.
It is created without error but when a insert is called on the table trigger error is shown
trigger failed -ORA-04098 is invalid and failed re-validation.
Guidance and suggestions will help a lot.
You should use:
REFERENCING new AS new
...
BEGIN
INSERT INTO fa1(s_id, name, class, sec)
VALUES (:new.reg_no, :new.name, :new.class, :new.sec);
...
see, this select statement is invalid, because there is no such table as inserted
select reg_no,name,class,sec
from inserted
EDIT if you want to log the inserted values into table fa1, you would do something like, if you had the following columns in table STUDENT_PERSONAL_DETAIL: reg_no,name,class,sec
create or replace trigger "STUDENT_PERSONAL_DETAIL_T1"
AFTER insert on "STUDENT_PERSONAL_DETAIL"
for each row
begin
insert into fa1 (s_id,name,class,sec)
values (:new.reg_no, :new.name, :new.class, :new.sec)
end;
Note the clause AFTER insert on "STUDENT_PERSONAL_DETAIL". I have omitted or update or delete to make sure this will only be triggered for newly inserted records. (because you tried to select from table 'inserted', I have concluded that's what you want to do)