After Update Trigger SQL - sql

Hey guys i created two tables in oracle sql, first one has 2 columns, and the second has 3 columns(one of them is a foreign key from Pk of first table).
I want to create a trigger that AFTER i update the column of the foreign key in second table, will update the other columns according to the value of the pk.
Table1(idF, name)
table2(id, idF, name)
I want to create a trigger that when i update idF(foreign key) in table2 will display the same name as in table1.

You can create trigger in oracle as follows:
Create or replace trigger trg_table2
Before update of idf on table2
For each row
When (old.idf <> new.idf and new.idf is not null)
Begin
Select name into :new.name
from table1
Where idf = :new.idf;
End;
/

you can use this after update trigger on table1
delimiter $$
create trigger MyTrigger after update on table1
for each row
begin
update table2 set name = new.name where idF = new.idF;
end$$

Related

How do I create this trigger?

I have two tables: table1 and table2. I have a trigger in table1 that inserts the current row into table2 based on some conditions. If the row gets inserted into table2, I want to delete that row from table1. Now in Oracle, it seems we cannot delete the current row from the trigger in table1 itself.
A row level trigger on a table can manipulate the data of the updated rows. It cannot perform additional dml on the table itself (select, insert, delete).
A possible solution is to create a view on table1 with an INSTEAD OF trigger that deletes from table1 and perform all insert/update/delete statements on the view instead of the table
Example: when test_table.name is updated to 'KOEN', then row itself will be deleted. This example shows just an ON UPDATE trigger but it can be done for INSERT/UPDATE/DELETE:
CREATE TABLE test_table (
id NUMBER
GENERATED BY DEFAULT ON NULL AS IDENTITY
CONSTRAINT test_table_id_pk PRIMARY KEY,
name VARCHAR2(100 CHAR)
);
CREATE VIEW test_table_v AS
SELECT
id,
name
FROM
test_table;
CREATE OR REPLACE TRIGGER test_table_v_bu
INSTEAD OF UPDATE ON test_table_v
FOR EACH ROW
DECLARE
BEGIN
-- do your stuff on the other table.
IF :NEW.NAME = 'KOEN' THEN
DELETE FROM test_table WHERE id = :NEW.ID;
END IF;
END;
/
koen>INSERT INTO test_table ( name ) VALUES ( 'JIM' );
1 row inserted.
koen>select * from test_table;
ID NAME
_____ _______
3 JIM
koen>update test_table_v set name= 'KOEN';
1 row updated.
stapp_dev--SAMPLEAPPS>select * from test_table;
no rows selected
koen>

Sqlite running update in insert trigger to execute update trigger

Using sqlite I want to have a field 'url' generated from the given 'id' using a trigger both on insert and on update. For example id: '1' => url: 'test.com/1'
The table looks like this:
CREATE TABLE t1 (
id TEXT,
url TEXT
);
Since sqlite can't run the same trigger for update and insert, I see two options to accomplish this.
Option A
run a trigger after insert, that updates the id to itself, which in turns triggers the update trigger
CREATE TRIGGER run_updates_on_insert AFTER INSERT ON t1
BEGIN
UPDATE t1 SET id = NEW.id WHERE id = NEW.id;
END;
CREATE TRIGGER set_url_on_update BEFORE UPDATE on t1
BEGIN
UPDATE t1 SET url = 'test.com/' || NEW.id WHERE id = OLD.id;
END;
Option B
replicating the logic in two separate triggers for update and insert
CREATE TRIGGER set_url_on_insert AFTER INSERT on t1
BEGIN
UPDATE t1 SET url = 'test.com/' || NEW.id WHERE id = NEW.id;
END;
CREATE TRIGGER set_url_on_update BEFORE UPDATE on t1
BEGIN
UPDATE t1 SET url = 'test.com/' || NEW.id WHERE id = OLD.id;
END;
Both of these options give me the desired results, I tend to favor Option A, as I only have to write the update logic once, but I was wondering if there are any other advantages/disadvantage to prefer one to the other?
EDIT: For this particular use case it is better to use generated column (see forpas answer below)
Since version 3.31.0 (2020-01-22) of SQLite, you can create generated columns (stored or virtual), so you don't need any triggers:
CREATE TABLE t1 (
id TEXT,
url TEXT GENERATED ALWAYS AS ('test.com/' || id) STORED
);

How to insert a record and return the primary key to update the foreign key in another table?

I need to add value to a foreign key column in a table (table1). For this I have to create a new record in another table (table2) and return the handle to update the column with foreign key in the first table (table1).
Also, when I insert the new record in table2, I need a value contained in table1 for one of the columns in table2.
UPDATE table1
SET table2_id = (INSERT INTO table2 (id, anumber, atimestamp, atext)
VALUES (nextval('seqtable2'), 0, NOW()::TIMESTAMP, table1.anumber::TEXT)
RETURNING id );
I believe that with the above script (even not working) it is possible to understand the problem. I wrote in the simplest and most summarized way.
I'm looking for a solution for PostgreSQL 9.4, but if there are alternatives to later versions, I'd like to know as well.
Thank you very much in advance.
You can use pg/psql as follows:
DO
$updatecode$
DECLARE
i int;
BEGIN
INSERT INTO table2 (id, anumber, atimestamp, atext)
VALUES (nextval('seqtable2'), 0, NOW()::TIMESTAMP, 2::TEXT)
RETURNING id into i;
UPDATE table1 SET table2_id = i WHERE ...
END;
$updatecode$
LANGUAGE plpgsql;
Edit:
I had to add a loop because I needed to change multiple records. Another change was to be able to use a value of table1 in the atext column while inserting the record into table2.
DO
$insertforupdate$
DECLARE
tbl1 table1%ROWTYPE;
tbl2_id INTEGER;
BEGIN
FOR tbl1 IN SELECT * FROM table1
LOOP
INSERT INTO table2 (id, anumber, atimestamp, atext)
VALUES (nextval('seqtable2'), 0, NOW()::TIMESTAMP, tbl1.anumber::TEXT)
RETURNING id INTO tbl2_id;
UPDATE table1 SET table2_id = tbl2_id WHERE id = tbl1.id;
END LOOP;
END;
$insertforupdate$
LANGUAGE plpgsql;

Values of the inserted row in a Trigger Oracle

I want a trigger that updates the value of a column, but I just want to update a small set of rows that depends of the values of the inserted row.
My trigger is:
CREATE OR REPLACE TRIGGER example
AFTER INSERT ON table1
FOR EACH ROW
BEGIN
UPDATE table1 t
SET column2 = 3
WHERE t.column1 = :new.column1;
END;
/
But as I using FOR EACH ROW I have a problem when I try it, I get the mutating table runtime error.
Other option is not to set the FOR EACH ROW, but if I do this, I dont know the inserted "column1" for comparing (or I dont know how to known it).
What can I do for UPDATING a set of rows that depends of the last inserted row?
I am using Oracle 9.
You should avoid the DML statements on the same table as defined in a trigger. Use before DML to change values of the current table.
create or replace trigger example
before insert on table1
for each row
begin
:new.column2 := 3;
end;
/
You can modify the same table with pragma autonomous_transaction:
create or replace trigger example
after insert on table1 for each row
declare
procedure setValues(key number) is
pragma autonomous_transaction;
begin
update table1 t
set column2 = 3
where t.column1 = key
;
end setValues;
begin
setValues(:new.column1);
end;
/
But I suggest you follow #GordonLinoff answere to your question - it's a bad idea to modify the same table in the trigger body.
See also here
If you need to update multiple rows in table1 when you are updating one row, then you would seem to have a problem with the data model.
This need suggests that you need a separate table with one row per column1. You can then fetch the value in that table using join. The trigger will then be updating another table, so there will be no mutation problem.
`create table A
(
a INTEGER,
b CHAR(10)
);
create table B
(
b CHAR (10),
d INTEGER
);
create trigger trig1
AFTER INSERT ON A
REFERENCING NEW AS newROW
FOR EACH ROW
when(newROW.a<=10)
BEGIN
INSERT into B values(:newROW.b,:newROW.a);
END trig1;
insert into A values(11,'Gananjay');
insert into A values(5,'Hritik');
select * from A;
select * from B;`

Trigger that checks if the same tuple exists in two different tables

I wrote the following code:
CREATE OR REPLACE TRIGGER CHECK_tuple
BEFORE INSERT ON tableB
FOR EACH ROW
DECLARE IS_JOIN BOOLEAN:=FALSE
BEGIN
SELECT tableB.column1, tableB.column2,
CASE
WHEN IS_JOIN:= FALSE THEN raise_application_error(-20101, 'ERROR.');
ELSE IS_JOIN:= TRUE
END AS CHCK_JOIN
FROM tableB
JOIN tableA
ON tableB.column1=tableA.column1 AND tableB.column2=tableA.column2;
END;
I have to check if a tuple (t1) exits in table A (with "tuple", i mean the entire row of the table with multiple columns). If exists, it has to match with t2 in table B. Before one inserts tuple t2 in table B, the trigger must activate. If t1 doesn't match with t2, the flag IS_JOIN will remain FALSE and Oracle SQL will give an error. Else, if t1 is equal to t2, IS_JOIN will be TRUE and no action will be take. I want this "check" to take place for each row that one will insert in table B. Is this the proper way to do it? If the task isn't clear, please ask for further info.
The proper way to do something like this:
CREATE OR REPLACE TRIGGER test_test_CHECK_tuple
BEFORE INSERT ON tableB
FOR EACH ROW
declare
v_cnt number(10);
BEGIN
SELECT count(*)
into v_cnt
FROM tableA
where column1=:new.column1
and column2=:new.column2;
if v_cnt= 0 then
raise_application_error(-20101, 'ERROR.');
end if;
END;
:new means, that are the values, you want to insert. There is no other way to use that values.
btw. that is not really how a foreign key works, since a foreign key is assigned to a primary key or unique key