How do I update table A while adding rows on table B? - sql

My table A is about item records in the stock and table B is about purchase record.
https://ibb.co/KyJzXZm
When customer makes a purchase, table B will be updated, showing the purchase_id, item_id and item_quantity. At the same time, the same item in table A will be updated and reduced by the quantity in table B. Therefore the item quantity in table A should be (4 - 3 = 1). Table A should be updated whenever I update table B. Does anyone know how to do it? Thank you!!!

I have figured out a way to do so.
Just create a log table for table B. Then create a trigger on "After Insert"
on table B, update the log table. By doing so, you will get a New.item_id and New.item_quantity. Then create another trigger, "After Insert" on table B, then update table A,
SET item_quantity = item_quantity - New.item_quantity WHERE item_id = New.item_id
Below is my original code,
DELIMITER //
CREATE TRIGGER purchase_log_insert
AFTER INSERT ON purchase
FOR EACH ROW
BEGIN
INSERT INTO log_purchase (action, purchase_id_new, item_id_new, purchase_quantity_new, timestamp)
VALUES ('insert', NEW.purchase_id, NEW.item_id, NEW.purchase_quantity, NOW());
END; //
DELIMITER ;
DELIMITER //
CREATE TRIGGER change_item
AFTER INSERT ON purchase
FOR EACH ROW
BEGIN
UPDATE item
SET item_quantity = item_quantity - NEW.purchase_quantity WHERE item_id = NEW.item_id;
END; //
DELIMITER ;

Related

How to create a trigger on table A that inserts/updates entity in table B?

I have tables TableAAA, TableBBB, TableCCC and TableCollected. The AAA/BBB/CCC tables have a DateTime column:
table_aaa: DateTime modified
table_bbb: DateTime modified
table_ccc: DateTime modified
I'd like to have a 1-1 trigger on each table that runs after inserting/updating. It should save the biggest DateTime from given table into the TableCollected table. So if TableAAA table contains 3 rows with dates 1980-01-01, 1990-01-01 and 2010-01-01 then in TableCollected I'd have a row that contains the name of the table (or some identifier, it's okay if I have to set it) and the biggest date table_collected: name (table_aaa), modified (2010-01-01).
If TableBBB has rows with 1999-01-01, 2012-04-01, TableCollected should have 2 rows:
name datetime
table_aaa 2010-01-01
table_bbb 2012-04-01
So TableCollected would hold the biggest DateTime of other tables. It should contain each table's DateTime value just once. The name is unique and if it inserted once, it should update every time a new row is inserted in table AAA/BBB/CCC and modified value is bigger than the old value.
You need to create 3 triggers for every table, one for insert, one for update and one for delete (if the most recently modified record is deleted):
CREATE TRIGGER table_aaa_insert AFTER INSERT ON table_aaa
BEGIN
INSERT OR REPLACE INTO TableCollected (name, modified)
SELECT 'table_aaa', max(modified) FROM table_aaa;
END;
CREATE TRIGGER table_aaa_update AFTER UPDATE ON table_aaa
BEGIN
INSERT OR REPLACE INTO TableCollected (name, modified)
SELECT 'table_aaa', max(modified) FROM table_aaa;
END;
CREATE TRIGGER table_aaa_delete AFTER DELETE ON table_aaa
BEGIN
INSERT OR REPLACE INTO TableCollected (name, modified)
SELECT 'table_aaa', max(modified) FROM table_aaa;
END;
Note that name must be a primary key or a unique field of TableCollected to take advantage of INSERT OR REPLACE
However, depending on the rate of insert/update/delete operations on those tables, it could be more efficient to replace your TableCollected table with a view which dynamically returns the desired values:
CREATE VIEW TableCollected (name, modified) as
SELECT 'table_aaa', max(modified) from table_aaa
UNION ALL
SELECT 'table_bbb', max(modified) from table_bbb
UNION ALL
SELECT 'table_ccc', max(modified) from table_ccc;
In both solutions, an index on modified field in tables aaa, bbb, and ccc would be beneficial to performance.
EDIT:
On second thought, a more efficient way which doesn't require to calculate max(modified) every time a record is inserted or updated is this:
CREATE TRIGGER table_aaa_insert AFTER INSERT ON table_aaa
BEGIN
UPDATE TableCollected SET modified=NEW.modified WHERE name='table_aaa' AND modified<NEW.modified;
END;
CREATE TRIGGER table_aaa_update AFTER UPDATE ON table_aaa
BEGIN
UPDATE TableCollected SET modified=NEW.modified WHERE name='table_aaa' AND modified<NEW.modified;
END;
DELETE trigger doesn't change because in that case you need to search for max(modified) anyway.
Note that this solution requires to pre-populate TableCollected with a row for each table. Also note that in the trigger modified refers to the TableCollected field, and NEW.modified refers to the table_aaa field which was just inserted or updated.
The answer to your question is Yes. Here is an example from the official docs:
CREATE TRIGGER update_customer_address UPDATE OF address ON customers
BEGIN
UPDATE orders SET address = new.address WHERE customer_name = old.name;
END;

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>

INSERT TRIGGER AFTER UPDATE ANOTHER TABLE

There are 2 tables orders and pizza. I have to create trigger update_order_pizza which will insert row in table order_pizza after new row is inserted in table order ( or when row is updated).
Code under trigger work when I launch in SQL, but I don't see what changes in table order_pizza after I inserted row in order.
CREATE DEFINER=`root`#`localhost` TRIGGER `update_order_pizza` AFTER INSERT ON `orders` FOR EACH ROW BEGIN
set #orderid = (select max(order_id) from orders);
set #pizzaid = (select max(pizza_id) from pizza);
insert into order_pizza(order_id,pizza_id)
values(#orderid,#pizzaid);
END
I expect to see next
If I insert new order , let;s say order id=36 in table order_pizza should be inserted new record (36,64)
Your code should be using the new variable to reference rows. In addition, your tables should be defining the ids as auto-increment.
So, the code should look more like this:
create trigger `update_order_pizza` after update on `orders`
for each row
begin
insert into order_pizza (order_id)
values (new.order_id);
end;
Alternatively, the pizza_id might be in the orders table, and you may intend:
insert into order_pizza (order_id, pizza_id)
values (new.order_id, new.pizza_id);

Delete after Insert trigger

I'm trying to create after insert trigger to delete a row from table whenever I insert the same row in the opposite table using the ID
But it doesn't work
Create Trigger [dbo].[MeritedDeceased] On [dbo].[Deceased]
After Insert
As
Begin
Delete From dbo.Merited Where dbo.Deceased.ID = dbo.Merited.ID
End
I think you mean to do something like this (maybe)...
CREATE TRIGGER [dbo].[MeritedDeceased] ON [dbo].[Deceased]
AFTER INSERT
AS
BEGIN
DELETE M
FROM [dbo].[MeritedDeceased] M
INNER JOIN Inserted I
ON I.ID = M.ID
;
END
;
Translation: Every time a row is inserted into dbo.Deceased, delete any rows with the same (inserted) ID from dbo.MeritedDeceased.
FYI, this TRIGGER won't just delete one row, but also a batch of rows that were inserted together. If that's what you want, then this should help.

how to create trigger on derived table?

I have created two tables customer and orders and I have already inserted some data in customer table but nothing is in orders table. Now I want to create a trigger on orders table that would copy only the id column ( which is defined in customer table as primary key) in orders table of o_id ( which is defined as foreign key in orders table ).
I want to check my created trigger and fix it if you find any error in it.
My trigger for orders table :
CREATE OR REPLACE TRIGGER tri_order
BEFORE INSERT
ON orders
FOR EACH ROW
BEGIN
SELECT ID
INTO :NEW.o_id
FROM customer;
END;
Thanks.
I want to create a trigger on orders table that would copy only the
id column
you can start doing like this , (by the way I didnt understand where you want to use your derived table ? what is the query)
CREATE OR REPLACE TRIGGER tri_order
BEFORE INSERT
ON orders
FOR EACH ROW
declare cnt number (3);
BEGIN
select count(1) into cnt from customer where id=:new.id; // its is checking
if cnt=0 then
insert into customer (id) values (:new.id);
end if;
// you can add raise error here
END;
/
you want to copy a value from customer table to orders table with help of trigger so firstly you will be needing to create the trigger on customertable not on orderstable ,since for every insert done in the customer table the trigger will be fired once which will insert a value in orders table.
CREATE OR REPLACE TRIGGER tri_order
AFTER INSERT
ON customer
FOR EACH ROW
BEGIN
INSERT INTO orders
(o_id)
SELECT :NEW.ID
FROM customer;
END;
You must specify a rule for finding the customer.
For example:
CREATE OR REPLACE TRIGGER tri_order
BEFORE INSERT
ON orders
FOR EACH ROW
BEGIN
SELECT c.ID
INTO :NEW.o_id
FROM customer c
WHERE c.customer_code = :NEW.customer_code;
END;