After Update PL/SQL Trigger between two Users - plsql

I have a Table A in Schema A and Table B in Schema B.
Schema B.Table B has Product Information taken from Schema A.Table A ( this is the main database for Products Profile).
When ever Update happens to products Information in Schema A.Table A, that Update should reflect in Schema B. Table B ?
How can i write trigger for it ?..
I have ProductID in both tables

Why not create a before update trigger? The inserts to tableB will only commit if the entire transaction commits.
EDIT: if you want updates to tableB, try this:
--drop table testtab_a;
create table testtab_a
(
col1 varchar2(10) primary key,
col2 varchar2(10)
);
--drop table testtab_b;
create table testtab_b
(
col1 varchar2(10) primary key,
col2 varchar2(10)
);
insert into testtab_a values ('A', 'B');
insert into testtab_a values ('X', 'B');
insert into testtab_a values ('Z', 'C');
insert into testtab_b values ('A', 'B');
insert into testtab_b values ('X', 'B');
insert into testtab_b values ('Z', 'C');
CREATE OR REPLACE TRIGGER testtab_tr
BEFORE UPDATE
ON testtab_a REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
begin
update testtab_b
set col1 = :new.col1,
col2 = :new.col2
where col1 = :old.col1;
end;
select * from testtab_a;
select * from testtab_b;
update testtab_a set col2 = 'H' where col1 = 'A';
EDIT2: If you need to go across schemas, you can use a dblink.
Inside trigger use:
update testtab_b#someSchema
set col1 = :new.col1,
col2 = :new.col2
where col1 = :old.col1;
Make sure you have proper grants setup by DBAs to do your updates, as well as any synonyms you may need (depending on your env).
Finally, if you are trying to keep these 2 tables in "sync", then don't forget about inserts and deletes (which can also be handled via similar trigger).
This is NOT the answer to replication, however, and this approach should be used very sparingly.

Related

Oracle 11g Triggers

I have create a table person(id, name ,samenamecount).The samenamecount attribute can be null but for each row can store the row count for same names.I am achieving this by calling a stored procedure inside a after insert trigger.Below is my code.
create or replace procedure automatic(s in person.name%type)
AS
BEGIN
update person set samenamecount=(select count(*) from person where name=s) where name=s;
END;
create or replace trigger inserttrigger
after insert
on person
for each row
declare
begin
automatic(:new.name);
end;
On inserting a row it is giving error like
table ABCD.PERSON is mutating, trigger/function may not see it.
Can somebody help me to figure out this?
If you have the table:
CREATE TABLE person (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT person__id__pk PRIMARY KEY,
name VARCHAR2(20)
NOT NULL
);
Then rather than creating a trigger, instead, you could use a view:
CREATE VIEW person_view (
id,
name,
samenamecount
) AS
SELECT id,
name,
COUNT(*) OVER (PARTITION BY name)
FROM person;
You can use the trigger:
CREATE TRIGGER inserttrigger
AFTER INSERT ON person
BEGIN
MERGE INTO person dst
USING (
SELECT ROWID AS rid,
COUNT(*) OVER (PARTITION BY name) AS cnt
FROM person
) src
ON (src.rid = dst.ROWID)
WHEN MATCHED THEN
UPDATE SET samenamecount = src.cnt;
END;
/
fiddle
If you want to make it more efficient then you could use a compound trigger and collate the names that are being inserted and only update the matching rows.

how to insert row on table B when table A is updated, using a trigger in SQLlite

Table A
userID
Name
Table B
UserID
Timestamp
I need to create a trigger to insert a row in table B, when A.Name changes. so far, i have:
CREATE TRIGGER NameUpdate
AFTER UPDATE OF Name
ON A
FOR EACH ROW
BEGIN
INSERT INTO B(
UserID,
Timestamp
)
VALUES (
xxxxxxx,
DateTime('now')
);
END;
XXXXXXX should be A.UserID that just changed.
You can refer to the before/after values (according to relevance i.e. only new for inserts, old or new for updates and only old for deletes) using a prefix of old. or new. respectively.
Try :-
CREATE TRIGGER NameUpdate AFTER UPDATE OF Name ON A FOR EACH ROW
BEGIN
INSERT INTO B( UserID, Timestamp ) VALUES ( new.UserID, DateTime('now') );
END
;
Or (as the UserID column hasn't changed) :-
CREATE TRIGGER NameUpdate AFTER UPDATE OF Name ON A FOR EACH ROW
BEGIN
INSERT INTO B( UserID, Timestamp ) VALUES ( old.UserID, DateTime('now') );
END
;

trigger to delete a record before insert

i have a table with 4 columns
1.msisdn
2.accountnumber
3.cardnumber
4.subscriptiondate
I want to add a trigger to this table. If the data i am inserting is
1.99999999
2.2
3.3298572857239
4.(this can be blank)
and the data that is currently in the table is
1.99999999
2.1
3.3298572857239
4.(this can be blank)
Trigger should check if there is this msisdn 99999999 is already having a record with this cardnumber 3298572857239. If there is a record already existing in the table, the trigger should delete the existing entry and insert the new one. The final result should look like this
1.99999999
2.1
3.3298572857239
4.(this can be blank)
I want to keep the value of accountnumber same before and after the trigger. This is what i have tried so far but for this trigger, i am not getting any data in accountnumber column. Please someone help
DROP TRIGGER TRIG_TABLEA;
CREATE OR REPLACE TRIGGER TRIG_TABLEA
BEFORE INSERT ON TABLEA
REFERENCING OLD AS Old NEW AS New
FOR EACH ROW
BEGIN
:new.accountnumber := :old.accountnumber;
DELETE FROM TABLEA WHERE MSISDN = :new.MSISDN AND CARDNUMBER = :new.CARDNUMBER;
:new.MSISDN := :new.MSISDN;
:new.CARDNUMBER := :new.CARDNUMBER;
:new.accountnumber := :old.accountnumber;
END;
/
Don't do a delete-and-insert. You want MERGE. The only thing that can change in your statement is accountnumber and subscriptiondate. You don't say where the data is coming from, so I assume this is a PL/SQL procedure with p_* as the parameters. So you want something like this:
MERGE INTO mytable trg
USING ( SELECT p_accountnumber, p_subscriptiondate FROM dual ) src
ON ( trg.msisdn = p_msisdn AND trg.cardnumber )
WHEN NOT MATCHED INSERT ( msisdn, accountnumber, cardnumber, subscriptiondate )
VALUES ( p_msisdn, p_accountnumber, p_cardnumber, p_subscriptiondate )
WHEN MATCHED SET ( cardnumber = p_cardnumber, subscriptiondate = p_subscriptiondate)
This will do an insert if the row doesn't exist or update an existing row if it does.

SQLITE fill value with unique random table

I want to create a table with a field that is unique and limited to a certain value. Lets say that the limit is 100, the table is full, I remove a random row, and when I create a new row it has the value that was freed before.
It doesn't need to be the fastest thing in the world (the limit is quite small), I just want to implement it in a DB.
Any ideas?
Create one more column in main table, say deleted (integer, 0 or 1). When you need to delete with certain id, do not really delete it, but simply update deleted to 1:
UPDATE mytable SET deleted=1 WHERE id = <id_to_delete>
When you need to insert, find id to be reused:
SELECT id FROM mytable WHERE deleted LIMIT 1
If this query returns empty result, then use INSERT to create new id. Otherwise, simply update your row:
UPDATE mytable SET deleted=0, name='blah', ... WHERE id=<id_to_reuse>
All queries reading from your main table should have WHERE constraint with NOT deleted condition:
SELECT * FROM mytable WHERE NOT deleted
If you add index on deleted, this method should work fast even for large number of rows.
This solution does everything in a trigger, so you can just use a normal INSERT.
For the table itself, we use an autoincrementing ID column:
CREATE TABLE MyTable(ID INTEGER PRIMARY KEY, Name);
We need another table to store an ID temporarily:
CREATE TABLE moriturus(ID INTEGER PRIMARY KEY);
And the trigger:
CREATE TRIGGER MyTable_DeleteAndReorder
AFTER INSERT ON MyTable
FOR EACH ROW
WHEN (SELECT COUNT(*) FROM MyTable) > 100
BEGIN
-- first, select a random record to be deleted, and save its ID
DELETE FROM moriturus;
INSERT INTO moriturus
SELECT ID FROM MyTable
WHERE ID <> NEW.ID
ORDER BY random()
LIMIT 1;
-- then actually delete it
DELETE FROM MyTable
WHERE ID = (SELECT ID
FROM moriturus);
-- then change the just inserted record to have that ID
UPDATE MyTable
SET ID = (SELECT ID
FROM moriturus)
WHERE ID = NEW.ID;
END;

Use trigger for auto-increment

I'm trying to solve the problem that composite keys in sqlite don't allow autoincrement.
I don't know if it's possible at all, but I was trying to store the last used id in a different table, and use a trigger to assign the next id when inserting a new reccord.
I have to use composite keys, because a single pk wouldn't be unique (because of database merging).
How can I set a field of the row being inserted based on a value in a different table
The query so far is:
CREATE TRIGGER pk BEFORE INSERT ON product_order
BEGIN
UPDATE auto_increment SET value = value + 1 WHERE `table_name` = "product_order";
END
This successfully updates the value. But now I need to assign that new value to the new record. (new.id).
If you use an AFTER INSERT trigger then you can update the newly inserted row, as in the following example.
CREATE TABLE auto_increment (value INT, table_name TEXT);
INSERT INTO auto_increment VALUES (0, 'product_order');
CREATE TABLE product_order (ID1 INT, ID2 INT, name TEXT);
CREATE TRIGGER pk AFTER INSERT ON product_order
BEGIN
UPDATE auto_increment
SET value = value + 1
WHERE table_name = 'product_order';
UPDATE product_order
SET ID2 = (
SELECT value
FROM auto_increment
WHERE table_name = 'product_order')
WHERE ROWID = new.ROWID;
END;
INSERT INTO product_order VALUES (1, NULL, 'a');
INSERT INTO product_order VALUES (2, NULL, 'b');
INSERT INTO product_order VALUES (3, NULL, 'c');
INSERT INTO product_order VALUES (4, NULL, 'd');
SELECT * FROM product_order;

Resources