I have 2 tables (in MySQL):
sales(sale_id, customer_id, sale_date, dicount, stock_item_id, seller_id, quantity)
record example:
a0018 | m9795 | 2017-10-2020 | 5 | MarFT | 0 | B-77028
stock(stock_item_id,supplier_name,supplier_email,supplier_phone,item_category item_name,wholesale_price,markup_price,items_in_stock)
record example:
B-77001 |BSN |direct#bsn.com | 1877333665 | Gainers | True Mass | 2.6kg | 33.75 |44.99 | 500
I need to create a trigger that will add a new record into sales table (recording a new sale, that will autoincrement). At the same time I want stock table to update 'items_in_stock' value (that should decrease by whatver quantity was just sold when there is match on stock_item_id)? I hope this makes sense. I'd appreciate any help. Thanks.
Use this:
DELIMITER $$
CREATE
TRIGGER `OnSalesInsert` BEFORE INSERT ON `Sales`
FOR EACH ROW BEGIN
UPDATE Stock
SET items_in_stock = items_in_stock - new.quantity
WHERE stock_item_id = new.stock_item_id;
END;
$$
DELIMITER ;
Related
I have 3 Mysql tables and I want to make one of the fields generated from multiplying two fields from two different tables. These are my tables:
ITEMS
id_item | price
1 | 20
2 | 30
3 | 50
DETAIL TRANSACTIONS
id_trans(fk) | id_item | total_items
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
TRANSACTIONS
id_trans | total_price
1 | 100
A total price field inside TRANSACTIONS is what I wanted, and I have tried making a trigger like:
CREATE TRIGGER total_price
AFTER INSERT ON detail_transactions
FOR EACH ROW
UPDATE transactions
SET transactions.`total_price`=
(SELECT SUM(items.'price'*detail_transactions.'total_items')
FROM items
JOIN detail_transactions
ON items.'id_item'= detail_transactions.`id_item`)
WHERE transactions.`id_trans` = NEW.`id_trans`;
But the result is not what I wanted. Any help will be appreciated!
Key words are FOR EACH ROW - ie update 1 row at a time..And do not assume transactions exists test and create if need be
drop trigger if exists t;
delimiter $$
create trigger t after insert on detail_transactions
for each row begin
if not exists (select 1 from transactions t where t.id_trans = new.id_trans) then
insert into transactions
select new.id_trans,new.total_items * price
from items
where items.id_item = new.id_item ;
else
update transactions join items on items.id_item = new.id_item
set total_price = total_price + (new.total_items * price);
end if;
end $$
CREATE TRIGGER tr_ai_update_total_price
AFTER INSERT
ON detail_transactions
FOR EACH ROW
REPLACE INTO transactions (id_trans, total_price)
SELECT NEW.id_trans, SUM(items.price * detail_transactions.total_items)
FROM items
JOIN detail_transactions USING (id_item)
WHERE transactions.id_trans = NEW.id_trans;
This query assumes that transactions (id_trans) is defined as UNIQUE (maybe PRIMARY KEY).
If the row for this id_trans already exists it will be replaced with new values. If it not exists then it will be inserted.
The trigger creation statement contains 1 statement, so neither BEGIN-END nor DELIMITER needed.
So, I have two tables: Transfers and Inventory.
What I am trying to do is when something is entered into the Transfer table, it will change an entry in the Inventory table.
An example of what I need is:
Say there is a man named Dr Jones and another man named Dr Smith. Dr Jones has £30 in his 'Total' and Dr Smith has £10. Now, say Dr Jones gives Dr Smith £10, I need the Inventory table to -£10 on Dr Jones' account total, and +£10 onto Dr Smith's account total. So therefore when you refresh the table, it states Dr Smith's balance in the total column as £20, and Dr Jones' balance as £20 now as well.
I want to do this through a trigger. I currently have the following:
DELIMITER $$
CREATE TRIGGER update_inventory_through_transfer AFTER INSERT ON Transfers
FOR EACH ROW
BEGIN
UPDATE Inventory
SET Inventory.total = SELECT SUM (IF (owner = NEW.owner, -total, total)) FROM Transfers WHERE owner = NEW.owner
END$$
DELIMITER;
Could anyone help me with where i'm going wrong?
Thanks
The structure of your db is not clear from your question but assuming transfer knows the owner and who funds are being transferred to then the trigger should contain 2 straightforward updates, since a trigger is FOR EACH ROW then there is no need so sum the transfers.
drop table if exists transfer,inventory;
create table transfer (owner int,total int,tfr_to int);
create table inventory (owner int,total int);
insert into inventory values
(1,30),(2,10);
drop trigger if exists t;
DELIMITER $$
CREATE TRIGGER t AFTER INSERT ON transfer
FOR EACH ROW
BEGIN
UPDATE inventory t1
SET t1.total = t1.total + new.total
where t1.owner = new.tfr_to;
update inventory t1
set t1.total = t1.total - new.total
where t1.owner = new.owner;
END $$
DELIMITER ;
insert into transfer values (1,10,2);
select * from transfer;
+-------+-------+--------+
| owner | total | tfr_to |
+-------+-------+--------+
| 1 | 10 | 2 |
+-------+-------+--------+
1 row in set (0.02 sec)
select * from inventory;
+-------+-------+
| owner | total |
+-------+-------+
| 1 | 20 |
| 2 | 20 |
+-------+-------+
2 rows in set (0.00 sec)
I want to apply the trigger in database when column_value match the particular scenario like
In goal table there are fields like goal, status, start_Date, end_Date
Now I want to change the status of goal. When user enter his/her goal, he/she filled end_Date. Now I want to change the status of goal when end_Date matched to current Date
Example:-
+------+--------+--------------+-------------+
| GOAL | STATUS | START_DATE | END_DATE |
+------+--------+--------------+-------------+
| 1 | Active | 2017-07-03 | 2017-07-09 |
+------+--------+------------+---------------+
When END_DATE equals to current Date, then I want to change status 'Active' to 'Finished'
I hope I am able to understand my question.
Thanks in advance!
Body of an oracle table level trigger would look like this...
BEGIN
IF INSERTING and (:new.end_date = sysdate) THEN
:NEW.goal_status := desired_value;
ELSIF UPDATING AND (:new.end_date = sysdate) then
:NEW.goal_status := desired_value;
END IF;
End;
The logic for this is
DROP TRIGGER IF EXISTS TB;
DELIMITER //
CREATE TRIGGER TB BEFORE INSERT ON T
FOR EACH ROW
BEGIN
IF NEW.START_DT = DATE(NOW()) THEN
SET NEW.STATUS = 'YES' ;
end if;
END //
DELIMITER ;
use sandbox;
DROP TABLE IF EXISTS T;
CREATE TABLE T(GOAL INT, STATUS VARCHAR(3), START_DT DATE,END_DATE DATE);
mysql> TRUNCATE TABLE T;INSERT INTO T VALUES(1,NULL,'2017-07-06','2017-07-06');SELECT * FROM T;
Query OK, 0 rows affected (0.73 sec)
Query OK, 1 row affected (0.06 sec)
+------+--------+------------+------------+
| GOAL | STATUS | START_DT | END_DATE |
+------+--------+------------+------------+
| 1 | YES | 2017-07-06 | 2017-07-06 |
+------+--------+------------+------------+
1 row in set (0.00 sec)
I'm having trouble referencing the current row in an AFTER DELETE trigger in MySQL. Pretend I have the following books table:
+----+------+----------+
| id | name | ordering |
+----+------+----------+
| 1 | It | 3 |
| 2 | Cujo | 1 |
| 3 | Rage | 2 |
+----+------+----------+
I want to create a trigger that will decrement all rows whose ordering value is greater than the ordering value in a row that is deleted. For example, if I do DELETE FROM books WHERE id = 2, I want the resulting table to look like:
+----+------+----------+
| id | name | ordering |
+----+------+----------+
| 1 | It | 2 |
| 3 | Rage | 1 |
+----+------+----------+
I've tried:
DROP TRIGGER IF EXISTS reorder_books_on_delete;
DELIMITER $$
CREATE TRIGGER reorder_books_on_delete
AFTER DELETE ON books
FOR EACH ROW
BEGIN
IF ordering > OLD.ordering
THEN
UPDATE books SET ordering = ordering - 1
WHERE id = id;
END IF;
END$$
DELIMITER ;
But this results in an error when I execute a DELETE on the table:
ERROR 1054 (42S22): Unknown column 'ordering' in 'where clause'
This refers to the if statement, so how do I reference the current row in an ON DELETE trigger? The column definitely does exist.
The reason why it fails is because there is no current row and hence, ordering column doesn't exist, it should be used in WHERE clause, like this:
DROP TRIGGER IF EXISTS reorder_books_on_delete;
DELIMITER $$
CREATE TRIGGER reorder_books_on_delete
AFTER DELETE ON books
FOR EACH ROW
BEGIN
UPDATE books SET ordering = ordering - 1
WHERE ordering > OLD.ordering;
END$$
DELIMITER ;
However, as per MySQL's documentation, you can't do this, it will return the following error:
SQL Error (1442): Can't update table 'books' in stored
function/trigger because it is already used by statement which invoked
this stored function/trigger.
So, you will have to run another UPDATE query after DELETE query in a single transaction to achieve this functionality.
As said by Darshan, you can't do this with a Trigger.... But, Procedure can make if for you !
DROP PROCEDURE IF EXISTS delete_book;
DELIMITER //
CREATE PROCEDURE delete_book(IN pId INT)
BEGIN
set #a = (
SELECT ordering
FROM books
WHERE id = pId
);
UPDATE books SET ordering = ordering - 1
WHERE ordering > #a;
delete from books
WHERE id = pId;
END
//
DELIMITER ;
And you just have, instead of your DELETE FROM books WHERE id = 4 to make a CALL delete_book(4);
I have two tables in a database named as follows:
1. state_master
+---------------+-------------------+
| state_id | state_name |
+---------------+-------------------+
| 1 | new |
| 2 | assigned |
| 3 | in_progress |
| 4 | on_hold |
| 5 | closed |
+---------------+-------------------+
2. store_complaint_state_count
+----------+-----+--------+------------+-------+------+
| store_id | new |assigned| in_progress|on_hold|closed|
| 101 | 1 |2 | 2 |0 |0 |
| 102 | 5 |4 | 1 |0 |2 |
+----------+-----+--------+------------+-------+------+
Now I want to add another row in state_master state_id =6 and state_name=reopen.
I want to create a trigger which can alter table store_complaint_state_count and add column reopen in it.
I've created a procedure:
CREATE DEFINER=`root`#`localhost` PROCEDURE `alterTablestorewisecomplaintcount`(in state int )
BEGIN
alter table storewisecomplaintcount
add column state INT UNSIGNED ZEROFILL NOT NULL DEFAULT 0;
END
And a trigger:
CREATE DEFINER = CURRENT_USER
TRIGGER `nxtlife_sfcms_db_v2`.`complaint_state_AFTER_INSERT`
AFTER INSERT ON `complaint_state`
FOR EACH ROW
BEGIN
call alterTablestorewisecomplaintcount(new.state_value);
END
But it throws an error at the time of insertion:
ERROR 1422: 1422: Explicit or implicit commit is not allowed in stored function or trigger.
you are not allowed to do ALTER or DROP operation on triggers. these are the implicit commits that you see in the error message (see more details here)
Even if it would be possible by some workaround, this is wrong design. If you could do what you wanted- the first insert to the table would add the column, and from then on- all other inserts would have failed since the column already exists
Trigger shouldn't be used that way; instead of every time altering the able and adding a column; you should use a single column say Status which will contain all the different status values like
store_complaint_state_count: Status varchar(20);
Status
new
assigned
in_progress
on_hold
closed
reopen
Then you can modify your trigger code to populate that value to store_complaint_state_count table
CREATE DEFINER = CURRENT_USER
TRIGGER `nxtlife_sfcms_db_v2`.`complaint_state_AFTER_INSERT`
AFTER INSERT ON `complaint_state`
FOR EACH ROW
BEGIN
INSERT INTO store_complaint_state_count (store_id, `Status`) VALUES(105, new.state_name);
END
Hi you can create table and log all events in table.
create table dbLOG (Id Int Identity(1,1),PostTime
VARCHAR(50),ServerName VARCHAR(25),UserName VARCHAR(15),CommandText
VARCHAR(MAX))
go
CREATE TRIGGER [db_LOG]
ON DATABASE
FOR create_table,alter_table,drop_table
,create_PROCEDURE, alter_PROCEDURE,drop_PROCEDURE
,ALTER_function,create_function,drop_function
,ALTER_trigger,create_trigger,drop_trigger
AS
SET NOCOUNT ON
DECLARE #xEvent XML
SET #xEvent = eventdata() --capture eventdata regarding SQL statement user have fired
INSERT INTO dbLOG VALUES(
REPLACE(CONVERT(VARCHAR(50), #xEvent.query('data(/EVENT_INSTANCE/PostTime)')),'T', ' '),
CONVERT(VARCHAR(25), #xEvent.query('data(/EVENT_INSTANCE/ServerName)')),
CONVERT(VARCHAR(15), #xEvent.query('data(/EVENT_INSTANCE/UserName)')),
CONVERT(VARCHAR(MAX), #xEvent.query('data(/EVENT_INSTANCE/TSQLCommand/CommandText)'))
)