I have the following product table
id | companyID | prodID | price | stock | stockAvailable | sumStock
1 A 2 10 5 4
2 B 2 50 10 5
I need to have a trigger when I update a product row that will update the sumStock.
I am new to Triggers, my attempt failed:
CREATE TRIGGER `SalesDB`.`stockSumUpdate` BEFORE UPDATE
ON SalesDB.Product FOR EACH ROW
BEGIN
SET Product.sumStock = Product.stock + Product.stockAvailable
END
My Goal is in this case to calculate the SUM(stock) AS stockSum Where ProductID=2
in this case that would be 15 and then add that to the sumStock. Then add the stockAvailable column to that as well. So in sumStock for both collumns I would have 24.
Result would be:
id | companyID | prodID | price | stock | stockAvailable | sumStock
1 A 2 10 5 4 29
2 B 2 50 10 5 29
Try this syntax:
CREATE TRIGGER `SalesDB`.`stockSumUpdate` BEFORE UPDATE
ON SalesDB.Product FOR EACH ROW
BEGIN
SET NEW.sumStock = NEW.stock + NEW.stockAvailable
END;
That adds within a row of a table.
To get the total, you would use something like:
CREATE TRIGGER `SalesDB`.`stockSumUpdate` BEFORE UPDATE
ON SalesDB.Product FOR EACH ROW
BEGIN
SET NEW.sumStock = (select sum(stock + stockAvailable)
from products where p.prodid = new.prodid and p.id <> id
) + NEW.stock + NEW.stockAvailable;
END;
Except, this still, doesn't do what you want. If you are updating multiple rows at a time, you will get different total stock values.
In other words, you are trying to update a group of rows whenever you update a single row. Gosh, when put like that, it doesn't seem like a good idea. The second set of udpates could update even more rows and so on and so on (it wouldn't happen because of the product).
Instead, create a table with product as a primary key and the stock available in that table (might be an existing table). Then update the summary table every time there is a change in this table.
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 3 tables Production, Stop_Prodcution and triggered_table.
production has a one to many realation with Stop_prodcution where a production can have a lot of stop prodcutions.
production table
-----------------------
id_prod | date
-----------------------
1 |20/03/2019
2 |18/04/2019
Stop_Production table
----------------------------
id_stop | name | id_prod
----------------------------
1 | Any reason | 1
2 | Lunch | 1
3 |damaged prod| 2
triggered_table
----------------------------
id|id_prod|date|id_stop|name
i've created 2 triggers:
after insert into production
for each row
insert into triggered_table
(id_prod,date) values (new.id_prod, curdate())
and the other one:
after update
set id_stop=new.id_stop,
name= new.name
where id_prod= new.id_prod
the problem is that a production record is able to have 2 or more stop_Production records so with the triggers that I have, it will update always the same record, but what I need is a new record with same information of production table and the information that differs from the new inserted row in stop_production, please tell me if I explained my self if not I'll try to be more clear.
This query will give you the results you want, without using a trigger:
SELECT
t1.id_stop,
t1.id_prod,
t1.`name`,
t2.date
FROM stop_production
LEFT JOIN production
ON (t1.id_prod = t2.id);
If you want to make a "table" out of this, you can create a view.
CREATE VIEW triggered_table AS (
SELECT
t1.id_stop,
t1.id_prod,
t1.`name`,
t2.date
FROM stop_production
LEFT JOIN production
ON (t1.id_prod = t2.id)
)
Then, if you want to SELECTfrom this "table", you can simply:
SELECT * FROM triggered_table;
i'm looking to figure out how i can update a row like a LIMIT 2,2 on a select
there is a little example:
col1 | col2
5 10
5 10
5 10
I want to update the 2nd row like this:
col1 | col2
5 10
1 10
5 10
i know the row number so i want something like that:
UPDATE table
SET col1 = 1
WHERE col1 = 5
LIMIT 2, 1
we cant use limit but i know this is achievable, HeidiSQL can do it and i'm trying to figure out how they are doing
thanks
If you need to update particular rows, you need a column or columns that can be used as primary key.
SQL works on sets of rows and you can only update rows that can be identified as belonging to the set.
For example, you can
UPDATE Customers SET Preferred=True WHERE TotalSales > 1000
which will set the "Preferred" flag for any customers that have sales over 1000. This might be one customer or a million or none.
The only way to do the single row update you asked about is to have some way to identify the row. In many database servers you can configure an IDENTITY or SEQUENCE column that will auto-assign each row a unique ID.
You can add an ID column with the IDENTITY property set, which would get you:
ID | col1 | col2
1 5 10
2 5 10
3 5 10
So updating that particular row would be:
UPDATE table SET col1 = 1 WHERE ID = 2
I have a table with three columns, I want copy/paste all three columns within the same table, however, of the three columns, I want to update two columns with new data specific for that day while keeping one column the same. For the following table:
ticket_number | book_id | log_id
------------- | ------- | ------
1 | 1 | 120
12 | 2 | 120
23 | 3 | 120
I want to:
1) Copy all columns and paste into the same table
2) change the ticket_number column with new data for that day (e.g. 2, 13, 25) as well as the log_id column with the id for the current day (e.g. 121), while keeping book_id column the same.
I have tried with no avail:
INSERT INTO ticket (ticket_number, book_id, log_id) SELECT (2,13,24), (book_id), (121) FROM ticket;
This the schema for reference
Your SELECT query needs to return the rows that you want to insert.
UPDATE: You can use a separate table, which might be easier. Something like this:
CREATE TABLE id_map (
old_ticket_number NUMBER,
new_ticket_number NUMBER
);
You could insert the values into this table.
You can then use this query:
INSERT INTO ticket (ticket_number, book_id, log_id)
SELECT
m.new_ticket_number,
t.book_id,
121
FROM ticket t
INNER JOIN id_map m ON t.ticket_number = m.old_ticket_number;
Does this so what you're looking for?
I have a table:
+--------+-------------------+-----------+
| ID | Name | Order |
+--------+-------------------+-----------+
| 1 | John | 1 |
| 2 | Mike | 3 |
| 3 | Daniel | 4 |
| 4 | Lisa | 2 |
| 5 | Joe | 5 |
+--------+-------------------+-----------+
The order can be changed by admin hence the order column. On the admin side I have a form with a select box Insert After: to entries to the database. What query should I use to order+1 after the inserted column.
I want to do this in a such way that keeps server load to a minimum because this table has 1200 rows at present. Is this the correct way to save an order of the table or is there a better way?
Any help appreciated
EDIT:
Here's what I want to do, thanks to itsmatt:
want to reorder row number 1 to be after row 1100, you plan to leave 2-1100 the same and then modify 1 to be 1101 and increment 1101-1200
You need to do this in two steps:
UPDATE MyTable
SET `Order` = `Order` + 1
WHERE `Order` > (SELECT `Order`
FROM MyTable
WHERE ID = <insert-after-id>);
...which will shift the order number of every row further down the list than the person you're inserting after.
Then:
INSERT INTO MyTable (Name, `Order`)
VALUES (Name, (SELECT `Order` + 1 FROM MyTable WHERE ID = <insert-after-id>));
To insert the new row (assuming ID is auto increment), with an order number of one more than the person you're inserting after.
Just add the new row in any normal way and let a later SELECT use ORDER BY to sort. 1200 rows is infinitesimally small by MySQL standards. You really don't have to (and don't want to) keep the physical table sorted. Instead, use keys and indexes to access the table in a way that will give you what you want.
you can
insert into tablename (name, `order`)
values( 'name', select `order`+1 from tablename where name='name')
you can also you id=id_val in your inner select.
Hopefully this is what you're after, the question isn't altogether clear.