After insert Trigger - sql

I'm trying to do a trigger which insert some into column after insert statement. For example I have table with column which looks:
Column1 Column2 Column3
And I'm inserting data into Column 1, Insert into Table(Column1) values ('256234','234234').
Now I would like automatically insert into COlumn2 TImestamp and into Column3 Value "Y", So output should looks:
Column1 Column2 Column3
256234 2015-10-28 08:48 Y
234234 2015-10-28 08:48 Y
Guys, could you help me with that? I tried to use cursor
Finally I got something like that:
create or replace trigger name
after insert on table
declare
c1 sys_refcursor;
idx varchar2(200);
begin
open c1 for select Column1 from table ;
loop
fetch c1 into idx;
exit when c1%NOTFOUND;
update table a1 set a1.Column2 = (select to_char(sysdate,'YYYYMMDDHHMISS') from dual) where Column1=idx;
update table a1 set a1.Column3 = (select 'Y' from dual) where Column1=idx;
end loop;
close c1;
end;
It works fine, but I'm wondering if there is some other better solution than that?

No need for a cursor or even an update:
create or replace trigger name
before insert on table_x
begin
:new.column2 := sysdate;
:new.column3 := 'Y';
end;
/
But you need a before trigger for this, because an after trigger cannot modify the newly inserted row.
But why don't you just define a default value for those columns, then you don't need a trigger at all:
create table table_x
(
column_1 integer,
column_2 date default sysdate,
column_3 varchar(1) default 'Y'
);

You can create trigger as similar :
CREATE OR REPLACE TRIGGER "TRG_NAME"
BEFORE INSERT ON "TABLE_NAME"
FOR EACH ROW
DECLARE
BEGIN
:NEW.Column2 := to_char(sysdate,'YYYYMMDDHHMISS');
:NEW.Column3 := 'Y';
END TRG_NAME ;
/
ALTER TRIGGER "TRG_NAME" ENABLE;
/
Hope this PL/SQL will help you..

Related

How to update a table with a trigger

I am trying to create a trigger that reads from table 2 and updates a column in table 1.
I tried with this method but an exception occurred: ORA-04091:table table1 is mutating .
CREATE OR REPLACE TRIGGER "TRG1"
AFTER INSERT OR UPDATE ON table1
FOR EACH ROW
BEGIN
UPDATE table1 SET name =(SELECT name FROM table2
WHERE table1.id = table2.id);
END;
Use a BEFORE UPDATE trigger (as you cannot modify values after they have been inserted or updated) and use the :NEW record (rather that trying to update the table and getting into an infinite loop of triggers):
CREATE OR REPLACE TRIGGER TRG1
BEFORE INSERT OR UPDATE ON table1
FOR EACH ROW
BEGIN
SELECT name
INTO :NEW.name
FROM table2
WHERE :NEW.id = id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
:NEW.name := NULL;
END;
/
fiddle
You can only update the name in a before trigger
CREATE OR REPLACE TRIGGER "TRG1"
BEFORE INSERT OR UPDATE ON table1
FOR EACH ROW
DECLARE new_name varchar2(100);
BEGIN
SELECT name INTO new_name FROM table2
WHERE :new.id = table2.id;
:new.name :=new_name;
END;
/
MTO was so nice to make a fiddle

ORACLE update with returning OLD and NEW values

Is there equivalent to this T-SQL query in PL/SQL (Oracle 12c)?
UPDATE A SET A.columnA = 10 WHERE A.columnB < 30 OUTPUT INSERTED.*, DELETED.*
The query updates table A and at the same time returns the status of the record before the update and after the update.
Trigger is not a solution for me as well as SELECT records before and SELECT records after updating.
Not a direct one, but using RETURNING INTO you will be able to achieve the same effect:
CREATE TABLE A(columnA VARCHAR2(10), columnB INT);
INSERT INTO A(columnA, columnB) VALUES ('Test', 10);
INSERT INTO A(columnA, columnB) VALUES ('Row 2', 20);
CREATE TABLE audit_table(col_new VARCHAR2(10),col_old VARCHAR2(10));
DECLARE
TYPE rec IS RECORD (actual A.columnA%TYPE, old A.columnA%TYPE);
TYPE col_a_t IS TABLE OF rec;
v_a col_a_t;
BEGIN
UPDATE (SELECT A.*, (SELECT A.columnA FROM dual) AS old_columnA FROM A)
SET columnA = 'XYZ'
WHERE columnB < 30
RETURNING columnA, old_columnA BULK COLLECT INTO v_a;
COMMIT;
-- printing for debug
FOR i IN v_a.first .. v_a.last LOOP
dbms_output.put_line('Old =>' || v_a(i).old || ' new => ' || v_a(i).actual);
END LOOP;
-- additional
FORALL i IN v_a.first .. v_a.last
INSERT INTO audit_table VALUES v_a(i);
COMMIT;
END;
/
SELECT * FROM A;
SELECT * FROM audit_table;
DBFiddle Demo
Idea taken from: Returning Old value during update

Set a value if null inserted in Oracle SQL

I have created a trigger, that will automatically set the first column values as subsequent factorial numbers. However, additionally, I would like to set the second column's value as the value of first incremented by 5, in case a null value is inserted. Here's what I try right now:
create or replace trigger test_tr
before insert on myT
for each row
begin
IF :new.mNumb is null
THEN
UPDATE myT
SET mNumb = :new.tab_id + 5;
END IF;
SELECT fac(test_seq.NEXTVAL)
INTO :new.tab_id
FROM dual;
end;
But clearly I'm missing something, as nothing happens, the inserted null is still empty.
Do not re-update the table in your trigger, update the row you're given directly:
...
IF :new.mNumb is null
THEN
:new.mNumb = :new.tab_id + 5;
END IF;
...
It all works as expected, using Emmanuel's suggestion to remove the update stmt, as far as I can tell. Here's the test case I used:
drop table test;
create table test (col1 number, col2 number);
create trigger test_trg
before insert on test
for each row
begin
IF :new.col2 is null
THEN
:new.col2 := :new.col1 + 5;
END IF;
:new.col1 := dbms_random.value;
end;
/
insert into test values (1, 1);
insert into test values (1, null);
insert into test values (null, null);
commit;
select * from test;
which produces the following output:
COL1 COL2
---------- ----------
.617580128 1
.030570358 6
.555066268
Maybe if you set :new.col1 before dealing with the null col2 scenario, that would work better for you? Doing that produces:
COL1 COL2
---------- ----------
.302670917 1
.024927489 5.02492749
.667568400 5.66756840

PL/SQL trigger to insert next value

I created a trigger which works like when I update/insert a row in one table, an insert of a row will a done in another table which contains a primary key.
Now when I insert a row in the first table I want the trigger to check the last value of primary key of another table and if that is null or '-' then I've to insert 1 into that primary key column so as to insert the remaining values.
I've written the code as follows:
create or replace trigger "T1"
AFTER
insert or update on "buses"
for each row
begin
-- Here I want to check the V_id on vehicles table, if that is null or '-' then insert V_id as 1 along with the below insert statement.
if :NEW."b_key" is not null then
INSERT INTO vehicles (b_KEY,B_NAME,ADDRESS_1,CITY,STATE,ZIP,PHONE,WEBSITE) VALUES (:new.b_KEY,:new.b_NAME,:new.ADDRESS_1,:new.CITY,:new.STATE,:new.ZIP,:new.PHONE,:new.WEBSITE);
end if;
end;
How to find the last b_id in the vehicles table, so that if that value is null or '-' insert b_id as 1, followed by the above insert statement in the same row.
By adding another trigger we can do that as follows:
create or replace TRIGGER "B_VEHICLES"
before insert on "buses"
for each row
declare b_number number;
begin
select max(B_ID) into b_number from Vehicles;
if :OLD."B_ID" is null and b_number is null then
select 1 into :new."B_ID" from dual;
else select b_number + 1 into :new."B_ID" from dual;
end if;
end;​

Insert/Update in PL/SQL

I have made a procedure in PL/SQL which inserts data from one table to another on basis of primary key. My procedure is working fine but i can't figure out how will i update column CODE_NUMBER of my table MAIN if primary key already exists.
Actually i want rows of MAIN table to get UPDATED when its has primary key and insert data from REGIONS when primary key does not exists.
DECLARE
variable number;
id number;
description varchar2 (100);
CURSOR C1 IS
select regions.REGION_ID variable
from regions;
BEGIN
FOR R_C1 IN C1 LOOP
BEGIN
select regions.REGION_ID,regions.REGION_NAME
into id,description
from regions
where regions.REGION_ID = R_C1.variable;
----If exists then update otherwise insert
INSERT INTO MAIN( ID, CODE_NUMBER) VALUES( id,description);
dbms_output.put_line( id ||' '|| 'Already Exists');
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
dbms_output.put_line( R_C1.variable);
END;
END LOOP;
END;
There's no need to do this with PL/SQL and cursors. What you really want to do is something like this:
MERGE INTO MAIN dst
USING (
SELECT regions.REGION_ID id,
regions.REGION_NAME description
FROM regions
) src
ON src.id = dst.id
WHEN MATCHED THEN UPDATE
SET dst.code_number = src.description
WHEN NOT MATCHED THEN INSERT (id, code_number)
VALUES (src.id, src.description)
Read more about the SQL MERGE statement in the documentation
I can not really see a point in doing a cursor in this case. Why can't you just do it like this:
--Update the rows
UPDATE MAIN
SET ID=regions.REGION_ID,
CODE_NUMBER=regions.[description]
FROM MAIN
JOIN regions
ON MAIN.ID=regions.REGION_ID;
--Insert the new ones
INSERT INTO MAIN(ID,CODE_NUMBER)
SELECT
regions.REGION_ID,
regions.[description]
FROM
regions
WHERE NOT EXISTS
(
SELECT
NULL
FROM
MAIN.ID=regions.REGION_ID
)