Oracle Trigger PLS 00103 - oracle

I am a novice in PL/SQL and DB objects. I have written an after insert trigger based on condition but I am getting PLS 00103 error encountered ;. Please help.
Below is my trigger script,
CREATE TRIGGER trigger1 AFTER INSERT
ON Table1
FOR EACH ROW
when (new.upper(Table1.column1)='ABC')
Declare
ITEM_CODE table2.ITEM_CODE%TYPE;
BEGIN
ITEM_CODE := :new.ITEM_CODE;
INSERT INTO table2( PK,ITEM_CODE,EVENT_NUMBER)
VALUES(EVENT_NUMBER_SEQ.NEXTVAL, ITEM_CODE,EVENT_NUMBER_SEQ.NEXTVAL);
END;
I am executing this script through Toad.
Thanks in Advance.

problem is here: when (new.upper(Table1.column1)='ABC') should be (when upper(new.column1) ='ABC')
Also you don't need declare variable only to assign value. Just use value directly.
CREATE TRIGGER trigger1 AFTER INSERT
ON Table1
FOR EACH ROW
when (upper(new.column1) ='ABC')`
BEGIN
-- IF (upper(:new..column1) ='ABC') THEN
INSERT INTO table2( PK,ITEM_CODE,EVENT_NUMBER)
VALUES(EVENT_NUMBER_SEQ.NEXTVAL, :new.ITEM_CODE,EVENT_NUMBER_SEQ.NEXTVAL);
--END IF;
END;

Related

Oracle update trigger on the same table

I want to update field data_aktualizacji when some row in the same table is updated. I created the following compound trigger.
CREATE OR REPLACE TRIGGER oferta_update_trigger
FOR UPDATE ON oferty
compound TRIGGER
id_oferty number(10);
AFTER EACH ROW IS
BEGIN
id_oferty := :new.idk;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
UPDATE oferty SET data_aktualizacji = SYSDATE WHERE idk = id_oferty;
END AFTER STATEMENT;
END;
/
When I want to update some record, I get the following error.
SQL Error: ORA-00036: maximum number of recursive SQL levels (50) exceeded.
How to solve this problem? I this that some loop is created, but I don't know, how to workaround this.
Update oracle to alter the column to default to sysdate
Alter table oferty alter column data_aktualizacji set default sysdate
No need for trigger at all
As Ctznkane525 wrote, you definitively should use default-value to perform this action.
If you don't want to use default you can modify new.data_aktualizacji:
CREATE OR REPLACE TRIGGER oferty_update_aktualizacji
BEFORE INSERT OR UPDATE
ON oferty
FOR EACH ROW
DECLARE
BEGIN
:new.data_aktualizacji:= sysdate;
END;

Using INSERT INTO... SELECT in TRIGGER

The question I am going to ask is already there. But I don't have answer for this.
Please refer the below link.
ORACLE TRIGGER INSERT INTO ... (SELECT * ...)
I have around 600 columns in a table. After each insert in this table I need to insert the new row in another backup table.
Please tell how to use "INSERT INTO TABLE_NAME2 SELECT * FROM TABLE_NAME1" query in trigger.
Note: Without specifying columns in insert or select clause
Structure of both table is same. Specifying all the column name in trigger is difficult and also if new columns added, we need to add in trigger as well.
SQL> CREATE or REPLACE TRIGGER emp_after_insert AFTER INSERT ON emp
FOR EACH ROW
DECLARE
BEGIN
insert into emp_backup values (:new.empid, :new.fname, :new.lname);
DBMS_OUTPUT.PUT_LINE('Record successfully inserted into emp_backup table');
END;
reference:
http://www.tech-recipes.com/rx/19839/oracle-using-the-after-insert-and-after-update-triggers/
You should use COMPOUND TRIGGER. This trigger should look like this:
CREATE OR REPLACE TRIGGER t_copy_table1
FOR INSERT ON table1
COMPOUND TRIGGER
v_id number;
BEFORE EACH ROW IS
BEGIN
v_id := :new.id;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
insert into table2 select * from table1 where id=v_id;
END AFTER STATEMENT;
END t_copy_table1;

Oracle auto increment trigger issue

I am having an issue when creating the auto increment trigger in Oracle 11g. If someone can point out what I am doing wrong, I would really appreciate it. My script for the sequence is this :
CREATE SEQUENCE SPSS_QUOTE_LINE_ITEMS_SEQ start with 1
increment by 1
minvalue 1;
The script for trigger:
CREATE OR REPLACE TRIGGER SPSSQUOTELINEITEMS_ON_INSERT
BEFORE INSERT ON SPSS_QUOTE_LINE_ITEMS
FOR EACH ROW
BEGIN
SELECT SPSS_QUOTE_LINE_ITEMS_SEQ.NEXTVAL
INTO :new.line_num
FROM dual;
END;
The error I am getting:
[Code: 900, SQL State: 42000] ORA-00900: invalid SQL statement
Thanks a lot.
The correct way of doing this to modify your trigger as below:
CREATE OR REPLACE TRIGGER SPSSQUOTELINEITEMS_ON_INSERT
BEFORE INSERT ON SPSS_QUOTE_LINE_ITEMS
FOR EACH ROW
BEGIN
:new.line_num := SPSS_QUOTE_LINE_ITEMS_SEQ.NEXTVAL;
--No need to write any Select Into statement here.
END;
Or if i follow your way then it goes like
CREATE OR REPLACE TRIGGER SPSSQUOTELINEITEMS_ON_INSERT
BEFORE INSERT ON SPSS_QUOTE_LINE_ITEMS
FOR EACH ROW
declare
var number;
BEGIN
SELECT SPSS_QUOTE_LINE_ITEMS_SEQ.NEXTVAL
INTO var
FROM dual;
:new.line_num :=var;
END;
You normally use the terms in a trigger using :old to reference the old value of the column and :new to reference the new value.

Will I miss any changes if I replace an oracle trigger while my application is running?

I'm wondering if I will miss any data if I replace a trigger while my oracle database is in use. I created a toy example and it seems like I won't, but one of my coworkers claims otherwise.
create table test_trigger (id number);
create table test_trigger_h (id number);
create sequence test_trigger_seq;
--/
create or replace trigger test_trigger_t after insert on test_trigger for each row
begin
insert into test_trigger_h (id) values (:new.id);
end;
/
--/
begin
for i in 1..100000 loop
insert into test_trigger (id) values (test_trigger_seq.nextval);
end loop;
end;
/
--/
begin
for i in 1..10000 loop
execute immediate 'create or replace trigger test_trigger_t after insert on test_trigger for each row begin insert into test_trigger_h (id) values (:new.id); end;';
end loop;
end;
/
ran the two loops at the same time
select count(1) from test_trigger;
COUNT(1)
100000
select count(1) from test_trigger_h;
COUNT(1)
100000
create or replace is locking the table. So all the inserts will wait until it completes. Don't worry about missed inserts.
I think you might be going about testing this in the wrong way. Your insert statements won't take any time at all and so the replacement of the trigger can fit in through the gaps between inserts. As least this is what I infer due to the below.
If you change your test to ensure you have a long running SQL statement, e.g.
create table test_trigger (id number);
create table test_trigger_h (id number);
create sequence test_trigger_seq;
create or replace trigger test_trigger_t
after insert on test_trigger for each row
begin
insert into test_trigger_h (id) values (:new.id);
end;
/
insert into test_trigger
select level
from dual
connect by level <= 1000000;
If you then try to replace the trigger in a separate session it will not occur until after the insert has completed.
Unfortunately, I can't find anything in the documentation to back me up; this is just behavior that I'm aware of.
Following URL answers that trigger can be modified while application is running. its will a "library cache" lock and NOT a "data" lock. Oracle handles it internally without you worrying abt it.
Check out question raised by Ben- Can a trigger be locked; how would one determine that it is?
-- Run this from session 2:
select * from v$access where object = upper('test_trigger_t');

Create trigger to insert into another table

I have some problem executing the trigger below:
CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW
DECLARE
varReadNo Int;
varMeterID Int;
varCustID Varchar(10);
BEGIN
SELECT SeqReadNo.CurrVal INTO varReadNo FROM DUAL;
Select MeterID INTO varMeterID
From Reading
Where ReadNo = varReadNo;
Select CustID INTO varCustID
From Address A
Join Meter M
on A.postCode = M.postCode
Where M.MeterID = varMeterID;
INSERT INTO BILL VALUES
(SEQBILLNO.NEXTVAL, SYSDATE, 'UNPAID' , 100 , varCustID , SEQREADNO.CURRVAL);
END;
Error Message:
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
Does it mean that I am not suppose to retrieve any details from table Reading?
I believe that the issue occur as I retrieving data from Table Reading while it is inserting the value:
SELECT SeqReadNo.CurrVal INTO varReadNo FROM DUAL;
Select MeterID INTO varMeterID
From Reading
Where ReadNo = varReadNo;
It's there anyway to resolve this? Or is there a better method to do this? I need to insert a new row into table BILL after entering the table Reading where the ReadNo need to reference to the ReadNo I just insert.
You cannot retrieve records from the same table in a row trigger. You can access values from actual record using :new and :old (is this your case?). The trigger could then be rewritten to
CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW
DECLARE
varCustID Varchar(10);
BEGIN
Select CustID INTO varCustID
From Address A
Join Meter M
on A.postCode = M.postCode
Where M.MeterID = :new.MeterID;
INSERT INTO BILL VALUES
(SEQBILLNO.NEXTVAL, SYSDATE, 'UNPAID' , 100 , varCustID , SEQREADNO.CURRVAL);
END;
If you need to query other record from READING table you have to use a combination of statement triggers, row trigger and a PLSQL collection. Good example of this is on AskTom.oracle.com
Make sure that you have the necessary permissions on all the tables and access to the sequences you're using in the insert.
I haven't done Oracle in awhile, but you can also try querying dba_errors (or all_errors) in order to try and get more information on why your SP isn't compiling.
Something to the tune of:
SELECT * FROM dba_errors WHERE owner = 'THEOWNER_OF_YOUR_SP';
Add exception handling in your trigger and see what is happening, by doing it would be easy for you to track the exceptions.
CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW
DECLARE
varCustID Varchar(10);
BEGIN
-- your code
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20299)));
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20298)));
END;
we can combined insert and select statement
CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW
DECLARE
varCustID Varchar(10);
BEGIN
insert into bill
values
select SEQBILLNO.NEXTVAL,
SYSDATE,
'UNPAID' ,
100 ,
CustID,SEQREADNO.CURRVAL
From Address A
Join Meter M
on A.postCode = M.postCode
Where M.MeterID = :new.MeterID;
END;
try the above code.

Resources