Statement level trigger - plsql

I have a trigger for a table called A_TAB which as only one column A of character type. and I have a another table DUP_A which has same column as TAB_A.Trigger for A_TAB as follows
create or replace trigger A_trig
before insert on A_TAB
for each row
declare
num1 varchar2(50):= null;
pragma autonomous_transaction;
begin
select Wm_Concat(a) into num1 from DUP_A;
if num1 is null
then
num1:=:new.a;
else
num1:=num1||','||:new.a;
end if;
insert into DUP_A values(num1);
delete from DUP_A where rowid<>(select max(rowid) from DUP_A);
commit;
end;
Here I'm concatenating all the values that in newly inserted and inserting it to a single column of DUP_A.
It's working fine but, I need statement level trigger with same functionality
Thank you

You cannot reference data (:new and :old) in a statement level trigger.

Removing "for each row" clause will change row level trigger to statement level trigger .But PL/SQL runtime engine creates and populates
two data structures(:new and :old) that functions much like records only When a row-level trigger is fired

Related

How do I make a trigger with an increment for the values in a column?

I have two tables TRIP and DRIVER. When a new set of values in inserted into TRIP (to indicate a new trip being made), the values in the column TOTALTRIPMADE (which is currently empty) in the table DRIVER will increase by one. The trigger should recognise which row to update with the select statement I've made.
This is the trigger I've made:
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE := OLD.TOTALTRIPMADE+1
WHERE (SELECT L#
FROM TRIP
INNER JOIN DRIVER
ON TRIP.L# = DRIVER.L#;)
END;
/
However I get this error:
ORA-04098: trigger 'CSCI235.UPDATETOTALTRIPMADE' is invalid and failed re-validation
What should I edit in my code so that my trigger works? Thanks!
One error you made is in trying to reference OLD.TOTALTRIPMADE in your SET clause since no alias OLD exists, and unless the table TRIP contains a TOTALTRIPMADE column then the :OLD record won't contain a TOTALTRIPMADE column either (note that since this is an insert trigger the :OLD record either won't exist or won't contain any meaningful data anyway). Another error is in your WHERE clause where you are selecting L# from TRIP joined to DRIVER, but you aren't linking it back to the DRIVER table that you are attempting to update. Instead just update DRIVER where L# is equal the :NEW value of L# from the trip table. The final error I noticed is your use of , the := assignment operator which is for PLSQL code, however you are using it within SQL so just use = without the colon:
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE = nvl(TOTALTRIPMADE,0)+1
WHERE L# = :NEW.L#;
END;
/
Your code has syntax error due to which the trigger is not compiling,I have modified the trigger and it should get compiled successfully with desired results.Please check and feedback.
Please find below the script to create table and compile the trigger,
drop table trip;
create table trip (trip_id number(10),L# varchar2(10));
drop table driver;
create table driver(driver_id number(10),TOTALTRIPMADE number(10),L# varchar2(10));
drop trigger updatetotaltripmade;
CREATE OR REPLACE TRIGGER updatetotaltripmade
AFTER INSERT ON trip
FOR EACH ROW
ENABLE
DECLARE
BEGIN
UPDATE DRIVER
SET TOTALTRIPMADE = nvl(TOTALTRIPMADE,0) + 1
WHERE DRIVER.L# = :new.L#;
END;
/
select * from ALL_OBJECTS where object_type ='TRIGGER';
Output is below from the tests i did on https://livesql.oracle.com/apex/
There are no issues in the code.The trigger is compiled successfully and is valid.

Oracle SQL Developer: Trigger

Hello PL/SQL Experts!!
Do you know how can I use the value 'Batman' in
INSERT INTO SUPERHEROES VALUES ('Batman');
so I can have the below output
1 row inserted.
You added Batman
when I run a trigger function? I used the statement below but it does not shows Batman. Thank you in advance! (NOTE: I'm just starting learning sql)
This is a code :
CREATE OR REPLACE TRIGGER TRIG_SUPERHEROES
BEFORE INSERT ON SUPERHEROES
FOR EACH ROW
ENABLE
DECLARE
V_USER VARCHAR(20);
SH_NAME VARCHAR(20);
BEGIN`enter code here`
SELECT USER INTO V_USER FROM DUAL;
DBMS_OUTPUT.PUT_LINE('YOU JUST ADDED NEW RECORD ' ||SH_NAME);
END;
You have to use :new.sh_name.
:old contains the old record state, :new contains the new record state in a for each row trigger.

Oracle (11g) compound trigger not updating CLOB data field

I tried searching for answers to this but couldn't really find anything useful. Either there isn't or my searching capabilities took a knock. Regardless, here's my situation:
I have a case where I've got 2 identical tables, Z_TEST and Z_TEST2. Call Z_TEST2 an audit table if you'd like.
Both have 2 columns, ID (number) and CFIELD (CLOB). Z_TEST has a trigger which will either insert or update Z_TEST2 (in effect only the CLOB field).
Scenario 1:
If I create the following trigger on Z_TEST, which is a normal trigger, the audit table gets updated too:
CREATE OR REPLACE TRIGGER Z_TEST_TRIG
AFTER INSERT OR UPDATE ON Z_TEST
FOR EACH ROW
Begin
If inserting then
Begin
insert into Z_TEST2 values(:new.ID, :new.CFIELD);
end;
end if;
if updating then
begin
update Z_TEST2 Set CFIELD = :new.CFIELD where ID = :new.id;
end;
end if;
End;
Scenario 2:
If I create the following trigger which is a compound trigger and make use of its "After each row" block, the audit table's CLOB updates with nothing, null:
create or replace trigger Z_TEST_TRIG
FOR UPDATE OR INSERT ON Z_TEST
COMPOUND TRIGGER
AFTER EACH ROW IS
Begin
If inserting then
Begin
insert into Z_TEST2 values(:new.ID, :new.CFIELD);
end;
end if;
if updating then
begin
update Z_TEST2 Set CFIELD = :new.CFIELD where ID = :new.id;
end;
end if;
END AFTER EACH ROW;
END Z_TEST_TRIG;
Does anyone have any idea why this would work for scenario 1, but not 2? Our WHOLE framework is based on scenario 2 (compound triggers) and I've only recently come across the need to use CLOB data types, and with it came this problem.
Why the difference and is my code missing something?
Having no time to linger on this issue I solved it by making use of a variable.
Declaring a CLOB variable in the declaration section and assigning the value of the :new.clob_field to it either in BEFORE EACH ROW, or AFTER EACH ROW, and using the variable in your insert/update statement rather than :new.clob_field within the trigger solves this issue.
I came across a lot of posts by people battling with this (compound triggers specifically, not simple triggers), so I hope the time i spent on this helps someone else and saves them time.
It would really be helpful to my sanity if anyone comes across this post who knows the reason why :new.clob_field loses its value in a compound trigger when used in insert/update statements in the BEFORE/AFTER each row section. It would be awful dying one day with this thought stuck in my mind...
I'll also make the assumption that this would work for BLOB as well (if that causes an issue).
Something like this.... you just need to add update clause
CREATE OR REPLACE TRIGGER after_row_insert
AFTER INSERT
ON Z_TEST
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
Begin
insert into Z_TEST2 values(:new.ID, :new.CFIELD);
End;

Is there a way to define the order of execution of my triggers in sqlite?

If have many on insert triggers for a table. Can i specify which trigger will be executed first when i insert values into my table using sqlite?
i thought of combining my triggers but the problem is that i have different when statements for each trigger and if i understand the doc correctly the when statement commes before my update/insert etc. statement.
CREATE TRIGGER trigger_name AFTER INSERT ON table_name
WHEN expr
BEGIN
update-stmt;
END;
Combine all of the triggers into one:
CREATE TRIGGER some_trigger
AFTER INSERT ON some_table
FOR EACH ROW BEGIN
-- statement 1;
-- statement 2;
-- statement 3;
...
-- statement n;
END;
If the trigger is to do an update, as in the OP's example, then this won't help. But if each trigger is just checking something and possibly raising an error, which I think is a pretty common case, then it is possible to pack them all into a single trigger procedure (with implicit order of execution) and to use different expressions with each:
CREATE TRIGGER some_trigger
AFTER INSERT ON some_table
BEGIN
SELECT RAISE(FAIL, "error message one") WHERE (<select-statement-one>) == <value-one>;
SELECT RAISE(FAIL, "error message two") WHERE (<select-statement-two>) == <value-two>;
...
END;
(Remember that the value of a subquery expression is the first row of the result from the enclosed SELECT statement.)

Value of a NEW variable on a trigger not changing, on plsql

I'm loading data through Oracle Apex utilities using a datasheet.
I want to make a trigger that checks for a value on the table from the data loaded, and then changes it depending on what it gets.
The table has 4 columns: id,name,email,type
The data to load is something like this: name,email,type
Now my trigger:
create or replace TRIGGER BI_USER
before insert ON USER
for each row
declare
begin
if :NEW.ID is null then
select USERID_SEQ.nextval into :NEW.ID from dual;
end if;
:NEW.TYPE := 'something else';
end;
The ID works great, it takes a number from the sequence, but :new.type isn't working, it doesn't change.
I also run the SQL insert separately and the same happens.
EDIT:
new.type type is char(1), I wrote it like this just for testing yet it doesn't change...
aah I'm dissapoint of myself, it throws the error just after reading the data and never fires the trigger.
What I was trying to do is that it will have the name of the TYPE column, and put the id from that table into the NEW.type
Is there a way to change the NEW type?
I see what you're trying to do. You want your table to accept an inserted record containing data that will not fit in the width of one of the fields, and you want to use a trigger to "fix" the data so that it will fit.
Unfortunately, this trigger will not help you because the data is validated before your triggers are fired.
An alternative way to get around this may be to use a view with an instead-of trigger. The view would have a column "TYPE" which is based on a string of length 9; the instead-of trigger would convert this to the CHAR(1) for insert into the underlying table.
Try this instead:
select 'something else' into :NEW.TYPE from dual;
If this syntax worked for ID it should also work for TYPE

Resources