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 ;
Related
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;
I have a table with around 17k unique rows for which I need to run these set of statements in sequence
INSERT INTO TABLE1 using MASTERTABLE data (MASTERTABLE have 6 column)
SELECT value of column ID (Primary Key) of newly inserted row from TABLE1
Update that ID value in TABLE2 using a Stored Procedure
I have tried:
while loop: took around 3 hours to complete the execution
cursor: cancelled the query after executing it overnight
In my understanding I can not use JOIN as I need to execute the statements in a sequence
The questions is not detailed enough. The general idea I would like to use something like this
-- create a output table to hold new id, and key columns to join later
DECLARE #OutputTbl TABLE (ID INT, key_Columns in MASTERTABLE)
INSERT INTO TABLE1
OUTPUT INSERTED.ID, MASTERTABLE.key_columns INTO #OutputTbl
SELECT *
FROM MASTERTABLE
UPDATE T2
SET ID = o.ID
FROM TABLE2 t2
INNER JOIN OutputTbl o
ON t2.key_column = o.key_column
Maybe you can consider a TRIGGER on TABLE1 from which to call the stored procedure on TABLE2, and then you can call your INSERT as you wish/need.. one by one or in blocks..
DROP TRIGGER TR_UPD_TABLE2
GO
CREATE TRIGGER TR_UPD_TABLE2 ON TABLE1 AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
DECLARE #columnID INT = NULL
IF (SELECT COUNT(*) FROM INSERTED)=1 BEGIN
-- SINGLE INSERT
SET #columnID = (SELECT columnID FROM INSERTED)
EXEC TableTwoUpdateProcedure #columnID
END ELSE BEGIN
-- MASSIVE INSERT (IF NEEDED)
SET #columnID = 0
WHILE #columnID IS NOT NULL BEGIN
SET #columnID = (SELECT MIN(columnID) FROM INSERTED WHERE columnID > #columnID)
IF #columnID IS NOT NULL BEGIN
EXEC TableTwoUpdateProcedure #columnID
END
END
END
END
I have 2 triggers for 2 tables. Both create numbers, one creates an articlenumber, the other an ordernumber.
Articlenumber:
ALTER TRIGGER [dbo].[trg_CreateArtikelnummer]
ON [dbo].[tblArtikel]
AFTER INSERT
AS
IF ((SELECT TRIGGER_NESTLEVEL()) < 2)
BEGIN
DECLARE #ArtikelID INT;
DECLARE #LfID INT; --supplierID
DECLARE #ProdID INT
-- ---Wein, Traubensaft, Sekt
SET #ArtikelID = (SELECT
CASE WHEN Artikelart = 'Wein' THEN 1
WHEN Artikelart = 'Traubensaft' THEN 2
WHEN Artikelart = 'Sekt' THEN 3
END AS ArtikelID
FROM inserted)
SET #LfID = (SELECT Lfid FROM inserted)
SET #ProdID = (SELECT ProdID FROM inserted)
SET #Prodid = (SELECT COUNT(ProdID)
FROM [dbo].[tblArtikel]
WHERE Lfid = #LfID)
UPDATE dbo.tblArtikel
SET Artikelnummer = CONVERT(INT, CONVERT(NCHAR(1), #ArtikelID) +
CONVERT(NCHAR(3), FORMAT(#LfID, '000')) + CONVERT(NCHAR(4), FORMAT(#ProdID,'0000')))
FROM inserted
INNER JOIN dbo.tblArtikel ON inserted.prodid = dbo.tblArtikel.prodid
This one fires IMMEDIATELY when inserting date in the table by hand (for test purpose) and displays the generated articlenumber instantely.
Ordernumber: should be build from the running number per year for each supplier, so 1703001 stands for year 2017, supplierID 03, ordernumber 001
ALTER TRIGGER [dbo].[trg_CreateBestellnummer]
ON [dbo].[tblOrders]
AFTER INSERT
AS
IF ((SELECT TRIGGER_NESTLEVEL()) < 2)
BEGIN
--set nocount on;
declare #Jahr int
declare #LfID int --supplierID
declare #OrderID int
declare #Order int
--declare #Bestelldatum date
set #Jahr=(select right(year(getdate()),2))
set #LfID=(SELECT Lfid from inserted)
--SELECT #OrderID=INSERTED.OrderID from inserted
set #Order=(SELECT count(OrderID) from [dbo].[tblOrders] where Lfid=#LfID and year(Bestelldatum)=Year(Getdate()))
Update dbo.tblOrders set Bestellnummer=convert(int,convert(nchar(2),#Jahr)+convert(nchar(2),FORMAT(#LfID, '00'))+convert(nchar(3),format(#Order,'000')))
from INSERTED inner join dbo.tblOrders on INSERTED.OrderID= dbo.tblOrders.OrderID
This one does NOT fire at once, when finishing inserting date into the table and does NOT display the generated ordernumber.
I get a red exclamation mark on the left side of the records saying something like "data are write protected. Execute query again".
When I click the execute button on the menue the the trigger fires and updates the correct ordernumber.
What can be the reason?
Thanks
Michael
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
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