update multiple rows with trigger after insert (sql server) - sql

I have a table orderDetails that contains the products of an order
productId
color
size
quantity
and a table stock
productId
size
color
stock
When a order is completed I use this query to insert the items in the table orderDetails
INSERT INTO orderDetail(orderId, productId, productColor, productSize, productQuantity , cost productName)
SELECT
#orderId, products_translations.id, cart.productColor, cart.productSize,
cart.productQuantity, cart.cost, products_translations.name
FROM cart
INNER JOIN products_translations ON cart.productID = products_translations.id
WHERE
(cart.cartId = #cartId) AND
(products_translations.language = 1)
Then I have a trigger on table orderDetails:
ALTER TRIGGER [dbo].[scalaProdotti]
ON [dbo].[orderDetail]
FOR INSERT
AS
DECLARE #size int
DECLARE #color char(6)
DECLARE #quantity int
DECLARE #product int
BEGIN
SELECT #size = productSize FROM inserted
SELECT #color = productColor FROM inserted
SELECT #quantity = productQuantity FROM inserted
SELECT #product = productId FROM inserted
UPDATE stock SET quantity = quantity - #quantity WHERE size=#size AND color=#color AND product=#product
END
With this trigger I want to decrease the stock, but only the first product is affected, the other quantities remain the same.
What am I missing?
Thank you.

The main point is: you're assuming that the trigger will be called for each row being inserted - this is not the case.
Your trigger will be called once per statement - but that statement can insert mulitple rows at once.
In such a case, the Inserted table inside the trigger will contain multiple rows and your statements:
SELECT #size = productSize FROM inserted
SELECT #color = productColor FROM inserted
SELECT #quantity = productQuantity FROM inserted
SELECT #product = productId FROM inserted
will fail or will happen to select only the first row inserted and disregard the rest of the inserts.
You need to rewrite your trigger to cope with the fact that Inserted can contain multiple inserted rows at the same time
Your code in the trigger should look something like this:
UPDATE stock
FROM Inserted i
SET
stock.quantity = quantity - i.quantity
WHERE
stock.size = i.size
AND stock.color = i.color
AND stock.product = i.product

Related

Make trigger with variables work for multiple row inserts

I have a warehouse database and want to implement a trigger which makes sure that the number of products returned by customers cannot exceed the number of products sold minus the number of products returned previously.
It works for one insert in the RETURNS table, but gives me an error if I insert multiple rows at once.
How can I fix that?
Thanks!
The tables affected are
SALES_ITEMS (PRODUCT, SALE, SALES_QUANTITY)
RETURNS (IDRETURN, PRODUCT, SALE, RETURN_QUANTITY)
CREATE TRIGGER tr
ON Returns
AFTER UPDATE, INSERT
AS
BEGIN
DECLARE #product INTEGER;
DECLARE #sale INTEGER;
SET #product = (SELECT PRODUCT FROM Inserted);
SET #sale = (SELECT SALE FROM Inserted);
IF (SELECT SUM(r.RETURN_QUANTITY)
FROM RETURNS r
WHERE r.PRODUCT = #product
AND r.SALE = #sale) > (SELECT s.SALES_QUANTITY
FROM SALE_ITEMS s
WHERE s.PRODUCT = #product AND s.SALE = #sale)
BEGIN
ROLLBACK TRANSACTION;
END
END
Hmmm . . . this is a bit complicated. One method is to join the returns and sales together to see if there are any cases where the returns exceed the sales:
if exists (select 1
from RETURNS r join
inserted i
on r.PRODUCT = i.product and r.SALE = i.sale join
sales_items si
on si.product = i.product and si.sale = i.sale
group by r.product, s.sales_quantity
having sum(r.return_quantity) > s.sales_quantity
)
begin
ROLLBACK TRANSACTION;
end;

Update table 1 when the column value of the table 2 changes ** Without Trigger **

I'm trying to update a column in table 1 when the value of the column in table 2 changes. I'm trying to avoid using a SQL Server trigger as I faced so many issues with the application when the trigger is enabled. Plus it has to be a instant update on table 2. Any help is highly appreciated.
Thanks
LOGIC
Get the status of the Maximum due date of the affected prodid and change the buyer in the table 2 for depend on the status
EDIT. I have added the trigger I used. but it is very in-efficient and caused issues
CREATE TRIGGER trg_Update
ON [dbo].[tblTable1]
AFTER UPDATE
AS
DECLARE
#v_orderId int,
#v_proId int,
#v_statusId int
BEGIN
SELECT #v_orderId = OrderID
FROM inserted
SELECT #v_proId = ProdID
FROM tblTable1
WHERE OrderID = #v_orderId
SELECT #v_statusId = v.VisitStatusID
FROM tblTable1 v
INNER JOIN
(
SELECT MAX(DueDate) AS MaxDueDate, ProdID
FROM tblTable1
GROUP BY ProdID
) t2 ON v.ProdID = t2.ProdID
AND v.DueDate = t2.MaxDueDate
WHERE v.ProdID = #v_proId
IF #v_statusId IN (5, 25)
BEGIN
UPDATE tblTable2 SET Buyer= 'CP1' WHERE ProdID = #v_proId
END
ELSE
BEGIN
UPDATE tblTable2 SET Buyer= 'CP2' WHERE ProdID = #v_proId
END
END

SQL insert trigger condition statement and multiple rows

Could you please help me to finish my trigger. What i got so far:
CREATE TRIGGER [dbo].[atbl_Sales_OrdersLines_ITrigGG]
ON [dbo].[atbl_Sales_OrdersLines]
FOR INSERT
AS
BEGIN
DECLARE #ID INT = (SELECT ProductID
FROM INSERTED)
DECLARE #OrderedQ INT = (SELECT SUM(Amount)
FROM atbl_Sales_OrdersLines
WHERE ProductID = #ID)
DECLARE #CurrentQ INT = (SELECT Quantity
FROM atbl_Sales_Products
WHERE ProductID = #ID)
DECLARE #PossibleQ INT = (SELECT Amount
FROM INSERTED
WHERE ProductID = #ID)
IF (#CurrentQ - #OrderedQ >= #PossibleQ)
ELSE
END
I need to complete the code. Can not figure out how to do it. I need that if condition is met - trigger would allow the insert. If else, trigger would stop the insert/or rollback and prompt a message that quantity is not sufficient.
Also, will this code work if insert is multiple lines with different product ids?
Thanks.
Something like this might work. This trigger checks the products that are in the insert, summing the total that have been ordered (now and in the past), and if any of them exceed the available quantity, the whole transaction is rolled back. Whenever writing triggers, you want to avoid any assumptions that there is a single row being inserted/updated/deleted, and avoid cursors. You want to just use basic set based operations.
CREATE TRIGGER [dbo].[atbl_Sales_OrdersLines_ITrigGG]
ON [dbo].[atbl_Sales_OrdersLines]
FOR INSERT
AS
BEGIN
IF (exists (select 1 from (
select x.ProductId, totalOrdersQty, ISNULL(asp.Quantity, 0) PossibleQty from (
select i.ProductId, sum(aso.Amount) totalOrdersQty
from (select distinct ProductId from inserted) i
join atbl_Sales_OrdersLines aso on aso.ProductId = i.ProductId
group by productId) x
left join atbl_Sales_Product asp on asp.ProductId = x.ProductId
) x
where PossibleQty < totalOrdersQty))
BEGIN
RAISERROR ('Quantity is not sufficient' ,10,1)
ROLLBACK TRANSACTION
END
END
I still think this is a horrible idea.
Try this,
CREATE TRIGGER [dbo].[atbl_Sales_OrdersLines_ITrigGG]
ON [dbo].[atbl_Sales_OrdersLines]
INSTEAD OF INSERT --FOR INSERT
AS
BEGIN
DECLARE #ID INT = (SELECT ProductID
FROM INSERTED)
DECLARE #OrderedQ INT = (SELECT SUM(Amount)
FROM atbl_Sales_OrdersLines
WHERE ProductID = #ID)
DECLARE #CurrentQ INT = (SELECT Quantity
FROM atbl_Sales_Products
WHERE ProductID = #ID)
DECLARE #PossibleQ INT = (SELECT Amount
FROM INSERTED
WHERE ProductID = #ID)
IF (#CurrentQ - #OrderedQ >= #PossibleQ)
BEGIN
INSERT INTO YOURTABLE (COLUMN1, COLUMN2, COLUMN3, ..)
SELECT COLUMN1, COLUMN2, COLUMN3, ..
FROM inserted
END
ELSE
BEGIN
RAISERROR ('Quantity is not sufficient' ,10,1)
ROLLBACK TRANSACTION
END

inserting from a table to another table and activeting trigger

INSERT INTO SaleItem (ProdId, SaleQuantity)
SELECT ProdId, BasketProdQuantity FROM Basket;
CREATE TRIGGER TRG_Stock_Decrease
ON SaleItem
AFTER INSERT
AS
DECLARE #ProdId INT
DECLARE #SaleQuantity INT
SELECT #ProdId=ProdId,#SaleQuantity=SaleQuantity FROM inserted
UPDATE Product SET ProdStockQuantity=ProdStockQuantity-#SaleQuantity WHERE ProdId=#ProdId
UPDATE Product SET ProdNoOfSold =ProdNoOfSold+#SaleQuantity WHERE ProdId=#ProdId
DELETE FROM Basket Where ProdId = #ProdId
When I insert datas from Basket to SaleItem it works well, but trigger only work for first id that inserted. How can I make it work for all ids?
EDIT!
I changed my trigger like this and it kinda worked I guess.
CREATE TRIGGER TRG_Stock_Decrease
ON SaleItem
AFTER INSERT
AS
BEGIN
UPDATE Product SET ProdStockQuantity = ProdStockQuantity - (Select SaleQuantity From inserted Where Product.ProdId = inserted.ProdId ) Where Product.ProdId IN (Select ProdId From inserted)
UPDATE Product SET ProdNoOfSold =ProdNoOfSold + (Select SaleQuantity From inserted Where Product.ProdId = inserted.ProdId ) Where Product.ProdId IN (Select ProdId From inserted)
DELETE FROM Basket WHERE Basket.ProdId IN (Select ProdId From inserted)
END
Is that correct?
No need for each row or nested selects, just inner join with inserted :)
CREATE TRIGGER TRG_Stock_Decrease
ON SaleItem
AFTER INSERT
AS
UPDATE P
SET ProdStockQuantity=ProdStockQuantity-i.SaleQuantity,
ProdNoOfSold =ProdNoOfSold+i.SaleQuantity
FROM Product P
INNER JOIN inserted i
ON P.ProdId=i.ProdId
DELETE B
FROM Basket B
INNER JOIN inserted i
ON i.ProdId = B.ProdId
add FOR EACH ROW
DROP TRIGGER `TRG_Stock_Decrease`;
DELIMITER //
CREATE TRIGGER TRG_Stock_Decrease
AFTER INSERT ON `TABLE` FOR EACH ROW
BEGIN
DECLARE #ProdId INT;
DECLARE #SaleQuantity INT;
SELECT #ProdId=ProdId,#SaleQuantity=SaleQuantity FROM inserted;
UPDATE Product SET ProdStockQuantity=ProdStockQuantity-#SaleQuantity WHERE ProdId=#ProdId;
UPDATE Product SET ProdNoOfSold =ProdNoOfSold+#SaleQuantity WHERE ProdId=#ProdId;
DELETE FROM Basket Where ProdId = #ProdId;
END; //
DELIMITER ;

SQL server update query to add totals

I have a table as below:
The first record Amount and TotalAmount are same
In the second record Amount is added from first row and current and TotalAmount is added
And so on....
Now if I update the second row from 1.25 to 2, then the TotalAmount for all subsequent records should be changed.
I need an update query for this.
I have seq_no and row no as reference and field Type is the reference
Ideally you should create a view or stored procedure that performs a running total, this is an example of one method using a subquery:
SELECT
Type,
Amount ,
Total =
(
SELECT SUM(Amount)
FROM SomeTable B
WHERE B.Type=A.Type AND B.RowNum <= A.RowNum
)
FROM SomeTable A
This is just one method (not necessarily the best). I would suggest you google 'Running totals in SQL' and familiarise yourself with the explanation of this and other methods their pros, cons and performance implications of each.
One question, what version of SQL server are you using?
If you can use row number as reference than you can try following query but storing totals in table is bad idea as mentioned in comment:
DECLARE #Temp TABLE
(
Amount float,
TotalAmount float,
Rownum int
)
INSERT INTO #Temp VALUES (1.25,1.25,1),(1.25,2.50,2),(10,12.50,3)
DECLARE #PreviousAmount AS FLOAT
SELECT #PreviousAmount = Amount FROM #Temp WHERE Rownum=1
DECLARE #NewAmount AS FLOAT = 2
UPDATE #Temp SET TotalAmount = TotalAmount - #PreviousAmount WHERE Rownum>=1
UPDATE #Temp SET Amount=#NewAmount, TotalAmount = TotalAmount + #NewAmount WHERE Rownum=1
UPDATE #Temp SET TotalAmount = TotalAmount + #NewAmount WHERE Rownum>1
SELECT * FROM #Temp
If you want to use triggers(which is not recommended).you can use this:
create trigger trigger_name
for update
as
declare #count int= (select count(*) from table)
declare #a int =1
while(#a<#count)
begin
update table
set total_amount=(select amount from table where row_number=#a) + (select amount from table where row_number=#a-1 )
where row_number!=1
set #a=#a+1
end
Go