I have a table of bids and everytime a bid is added in an auction I want to create new notifications to every bidder in that auction. As this is for a class of databases I though of doing a trigger to show some skills in oracle pl/sql.
My trigger is like this:
CREATE OR REPLACE TRIGGER create_notifs
AFTER INSERT ON bid
FOR EACH ROW
BEGIN
INSERT INTO notification(id_notif, id_auction, username, time, seen_state)
SELECT notif_id_seq.NEXTVAL, :NEW.id_auction, username, SYSDATE, 0
FROM bid
WHERE bid.id_auction = :NEW.id_leilao;
END;
/
Now this trigger won't work because it's accessing the table that fired it. It is not a problem though because I'm not changing it and it really needs to be after the insertion because I need to see if it passes the constraints. How can I do this?
You can't do a SELECT from the table on which a row trigger is declared or you get the dreaded "mutating table" error, but it doesn't look to me like you need to SELECT anything. Try rewriting your trigger as:
CREATE OR REPLACE TRIGGER create_notifs
AFTER INSERT ON bid
FOR EACH ROW
BEGIN
INSERT INTO notification
(id_notif, id_auction, username, time, seen_state)
VALUES
(notif_id_seq.NEXTVAL, :NEW.id_auction, username, SYSDATE, 0);
END;
Best of luck.
Related
In my application, I have a trigger defined to do insertion for a table and a view, all the entries inserted are perfect, except for the date parameter, which gets inserted as '30/05/9305 22:58'. The values that the trigger gets is through the UI, I have checked the entire workflow from the java code from getting the values from the UI to passing it to the trigger, everything looks perfect.
Can anyone help me identify what is going wrong and where?
Date selected was 07/02/2018 which got transformed to 30/05/9305 22:58
Here is a short snap of the trigger that is being used for this:
create or replace trigger "TEST_TRIGGER"
instead of insert on "MY_VIEW"
referencing NEW as n
for each row
BEGIN
insert into DEMO_TABLE
(id, emp_name,report_date,insert_date)
select
demo.table_seq.nextval,:n.id,:n.emp_name,:n.report_date,sysdate from dual;
END;
Your insert statement could be wrong. it has extra column in the select
insert into DEMO_TABLE
(id, emp_name,report_date,insert_date)
select
:n.id,:n.emp_name,:n.report_date,sysdate from dual;
I have a trigger:
create or replace trigger trig
before insert on sistem
for each row
declare
v_orta number;
begin
SELECT v_orta INTO :new.orta_qiymet
FROM sistem;
v_orta:=(:new.riyaziyyat+:new.fizika)/2;
insert into sistem(orta_qiymet)
values(v_orta);
end trig;
When I insert a row:
insert into sistem(riyaziyyat,fizika) values(4,4)
I get an error:
Why am I getting that error?
This is fundamentally not understanding how triggers work. You can't generally select from the table the trigger is against, and a before-insert trigger shouldn't not insert into the same table again - as that would just cause the trigger to fire again, infinitely (until Oracle notices and stops it). You aren't even currently using the v_orta value you're attempting to query.
I suspect you think the trigger is instead of your original insert perhaps, and really you want to set the orta_qiymet value in the newly-inserted row automatically based on the other two columns you have supplied. To do that you don't (and can't) select those values; instead you refer to the :NEW pseudorecord as you are already doing, and then set the third column value in that same pseudorow:
create or replace trigger trig
before insert on sistem
for each row
begin
:new.orta_qiymet := (:new.riyaziyyat + :new.fizika)/2;
end trig;
/
There is a lot of information in the documentation; this is similar to one of the examples.
I am currently doing a homework assignment and am getting stuck at a point.
I want to create a trigger for auditing, and Yes I do know FGA, but that's not what was asked.
My trigger needs to record the current SQL for auditing. This is what I have now.
Imagine I have my table already created to store the inserting value.
CREATE OR REPLACE TRIGGER ALL_SQL_AUDIT
AFTER UPDATE ON SCOTT.EMP
FOR EACH ROW
BEGIN
INSERT INTO ALL_SQL_AUDIT(TABLE_NAME, SQL_TEXT, SQL_TYPE, CHANGE_DATE, DB_USERNAME, OS_USERNAME)
SELECT 'SCOTT.EMP',
SYS_CONTEXT('USERENV','CURRENT_SQL'),
'UPDATE',
SYSDATE,
USER,
SYS_CONTEXT('USERENV','OS_USER')
FROM dual;
END;
/
Problem is SYS_CONTEXT('USERENV','CURRENT_SQL') never return anything, so does anyone know how to get the current DML that triggered this event?
I have a table participants having structure as shown below:
Pid number
name varchar2(20)
version number
Whenever i inserted any record in participants table ,version =1 get populated.
For Example ,if i inserted pid=1 ,name='Gaurav' then record with version =1 get populated in participants table .
Now my issue is with update on participants table,
Suppose i am updating name ='Niharika' for pid=1 in participants table then a new record with pid=1 ,name='Niharika' and version =2 need to be created on the same table .
Again i update name='Rohan' for pid='1' in participants table a new record with pid=1 ,name='Rohan' and version=3 needs to be created .
How can i achieve this , clearly speaking i need to get max(version)+1 for that pid that is going to update .
I can achieve this using view and insert into view using instead of trigger ,but i am not satisfied with my solution .
I have also created compound trigger ,even that is not working for me because inside trigger i need to use insert statement for that table and this will give me recursive error
You should really have two tables. Make one with the structure you described as a "logging" table. It will keep the history of all the records. Have another table which is considered "current" which is the same but without the version column. Then, when inserts/update occur on the "current" tables' records, have a mechanism (trigger, for example) SELECT FOR UPDATE the max(version) in the logging table, add one, and insert into the logging table. This way, you're not going to run into mutating table errors or anything weird like that. There is a bit of serialization this way, but it's the closest to what you're trying to do.
Not usually recommended, but here's how you can do it anyways with no other extra logging table(s)-
CREATE or REPLACE
TRIGGER part_upd
AFTER UPDATE of name
ON participants
FOR EACH ROW
DECLARE
retval BOOLEAN;
BEGIN
retval := insert_row(:old.pid,:new.name);
END part_upd;
The function-
CREATE or REPLACE
FUNCTION insert_row (pid1 number, name1 varchar2)
RETURN boolean
IS
PRAGMA autonomous_transaction;
BEGIN
INSERT INTO participants
SELECT pid1, name1, max(vers)+1
FROM participants
WHERE pid = pid1;
COMMIT;
RETURN true;
END;
You'll have to fine tune the Trigger and Function properly by adding logging and exception handling. Read more about autonomous_transaction.
I have a trigger that looks something like this:
create or replace
TRIGGER cluster_check
before insert on my_table
FOR EACH ROW
when (passive_server = new.server)
begin
ROLLBACK;
UPDATE my_table
set (server,passive_server) = (passive_server,server) where passive_server = new.server;
end;
I am getting the error Error: ORA-04076: invalid NEW or OLD specification on compilation.
Essentially what I am trying to do is check on insert to see if the incoming server matches the passive server in another record and if so cancel the insert and swap the existing records passive and active servers.
What am I doing wrong?
A trigger on a table can't change the operation like this.
You could define a view on top of my_table, do the INSERT against the view, and then have an instead of insert trigger that changed the INSERT operation into an UPDATE. But then all your DML would have to go against the view rather than the table. You could potentially rename the table and then create a view named my_table to make that transition easier.
Before you go down that path, however, are you certain that you need a trigger in the first place? Are you sure that your application couldn't do something like call a stored procedure that would determine what to do or that it couldn't do a MERGE instead of an INSERT?