I'm fairly new to SQL Server and I'm having trouble implementing a WHERE statement inside a CASE, specifically for a trigger I'm working on.
I have 2 tables with the following fields:
Receipt(ItemID,Quantity)
and
Warehouses(WarehouseID,Stock)
|WarehouseID|Stock|
-------------------
|ARM01 |100 |
|ARM02 |100 |
The trigger checks whether a row with a specific quantity of any given item was inserted, altered or removed to Receipt and then subtracts or adds to the Stock of the Warehouses table.
So if I add a row with 200 Quantity in Receipt, it will subtract 100 from the Stock of WarehouseID 'ARM01', and if there is no Stock left in 'ARM01' (which there isn't because there is only 100), it will subtract the other 100 from 'ARM02'. Of course if 'ARM02' has a Stock of 0 it will print an error but I'll worry about that later.
The thing is, SQL Server doesn't accept a WHERE inside a CASE, because, of course, the entire CASE is already part of the SET statement and WHEREs only come after a SET. It's weird but I couldn't find an answer online yet for such a simple thing.
My goal:
CASE 1
UPDATE 'Stock of Table' where 'WarehouseID of Same Table' = 'ARM01'
CASE 2
UPDATE 'Stock of Table' where 'WarehouseID of Same Table' = 'ARM02'
I also realize the calculus for Stock -/+ Quantity and vice-versa might be wrong right now and I also have 2 statements in parenthesis after a THEN, separated by a AND because I was trying to distribute the first 100 to ARM01 and the rest to ARM02. That's probably very, very misguided and apologies for the incorrect code but for now I just want to figure out where to use a WHERE statement.
CREATE TRIGGER SubtractStock ON Receipt
FOR INSERT, UPDATE, DELETE
AS
[snipped UPDATE for deleted because it only exchanges '+' for '-' in the operation]
UPDATE Warehouses
SET Stock =
(CASE
WHEN inserted.Quantity <= Stock THEN Stock - Quantity WHERE WarehouseID = 'ARM01'
WHEN inserted.Quantity > Stock THEN (Stock - Quantity WHERE WarehouseID = 'ARM01')
AND (Quantity - Stock WHERE WarehouseID = 'ARM02')
END)
FROM inserted JOIN Warehouses ON inserted.ItemID = Warehouses.ItemID
Thank you!
I hate triggers, and this is a bad idea for one. With that out of the way.
For ARM01, move the WHERE to the WHEN with an AND:
SET Stock =
(CASE
WHEN inserted.Quantity <= Stock AND WarehouseID = 'ARM01'
THEN Stock - Quantity
...
The next problem is you need to see two rows to set the stock for ARM02, what the stock is in ARM02 to see if you need to subtract from ARM02, and the stock in ARM02 to subtract from. So moving the condition in the where somewhere else won't help. Probably two update statements, update ARM01, with an output clause to temp table or table valued variable to give before stock values for ARM01, then use that to update the values for ARM02.
Again, this sort of complicated logic rarely is appropriate inside a trigger.
Please try like this...Use proper aliases..
CREATE TRIGGER SubtractStock ON Receipt
FOR INSERT, UPDATE, DELETE
AS
UPDATE W
SET Stock = CASE
WHEN WarehouseID = 'ARM01' AND I.Quantity <= Stock THEN Stock - Quantity
WHEN WarehouseID = 'ARM01' AND I.Quantity > Stock THEN Stock - Quantity
WHEN WarehouseID = 'ARM02' THEN I.Quantity - Stock
END
FROM inserted I JOIN Warehouses W ON I.ItemID = W.ItemID
Related
Background
I am currently working on a simple access database for a small bookstore. The business sells books as well as other items.
See following ER-diagram here
Problem
My problem starts in the table Transaction. I would like to create a simple form where a subtotal is calculated as quantity purchased multiplied by the price (both of a certain item).
However the Price field is either in the BookInfo, FoodAndBev, or ApparelAndSupplies table.
Question
How can I traverse the Transaction table to Items and to one of the tables I listed depending on the StockNum in Transaction?
For example, a customer buys an item with StockNum BK001. I would like to retrieve the Price corresponding to BK001 in the BookInfo table and return to Transaction to be used for calculating the subtotal.
The field StockNum exists in tables BookInfo, FoodAndBev, and ApparelAndSupplies.
Sample Data: BookInfo, Items, Transaction
Ideal Output: Transaction 1: A customer buys 2 copies of a book with StockNum 'BK001' (disregard what I already have in the screenshot). The Price of 'BK001' is $119.99 which I would need to retrieve from BookInfo (my problem is I want to make sure it goes to BookInfo not the other two tables which have StockNum also), so the subtotal would then be calculated and would show $239.98. For now, I've been doing this manually. I want to be able to do this with different StockNum such as those that start with AS for Apparel and Supplies and FB for food and beverage.
Thanks in advance!
Left-Joining all tables and using Case-When-Expression (which is function switch in Access) for different price multiplication:
SELECT t.StockNum, t.NumOrdered,
switch(
Left(t.StockNum,2) = 'BK' , (t.NumOrdered * b.Price),
Left(t.StockNum,2) = 'AS' , (t.NumOrdered * a.Price),
Left(t.StockNum,2) = 'FB' , (t.NumOrdered * f.Price),
) AS subtotal
FROM Transaction t
LEFT JOIN BookInfo b ON b.StockNum = t.SockNum
LEFT JOIN ApparelAndSupplies a ON a.StockNum = t.SockNum
LEFT JOIN FoodAndBev f ON f.StockNum = t.SockNum
I want to create a view, whereby all post stock transactions will post on one line, as per my SQL Statement below, I get all transactions, but each is on a new line. I want the arrangement to be each new stock item on a new line, with "QtyOnHand" as the next column. Then I need all the QtyOut transactions to sum up in one column and all QtyIn to sum in another. Is this possible?
SELECT
StkItem.ItemGroup
,StkItem.Qty_On_Hand AS QtyOnHand
,PostST.TrCodeID
,PostST.Description
,PostST.Quantity
,PostST.Reference
,PostST.Order_No
,PostST.fQuantityInvoiced
,PostST.QuantityR
,PostST.TxDate
,PostST.Debit
,PostST.Credit
,Concat(StkItem.Description_1, ' - ',StkItem.Code) AS ItemAndCode
FROM PostST
INNER JOIN StkItem
ON StkItem.StockLink = PostST.AccountLink
The below picture shows how this statement currently shows - you can see on the far right how the same stock code is repeated for each transaction, as I would rather the stock item show once, and the transactions be summed.
This data will be dumpted into Excel and then used to create a stock turnover report.
Thank you!
You have to use SUM() and GROUP BY. Maybe that is what you need
SELECT
StkItem.ItemGroup
,SUM(StkItem.Qty_On_Hand) AS QtyOnHand
,PostST.TrCodeID
,PostST.Description
,SUM(PostST.Quantity) as Quantity
,PostST.Reference
,PostST.Order_No
,SUM(PostST.fQuantityInvoiced) as fQuantityInvoiced
,SUM(PostST.QuantityR) as QuantityR
,PostST.TxDate
,SUM(PostST.Debit) as Debit
,SUM(PostST.Credit) as Credit
,Concat(StkItem.Description_1, ' - ',StkItem.Code) AS ItemAndCode
FROM PostST
INNER JOIN StkItem
ON StkItem.StockLink = PostST.AccountLink
GROUP BY
StkItem.ItemGroup
,PostST.TrCodeID
,PostST.Description
,PostST.Reference
,PostST.Order_No
,PostST.TxDate
,StkItem.Description_1
,StkItem.Code
I'm using HP Vertica 7 as data warehouse DB.
I need to update two tables at the same time.
foreach (row r in table_1)
{
foreach (row r2 in table_2)
{
if(r.key1 == r2.key1 && r.key2 ==r2.key2 && r.soldQuantity > r2.Quantity)
{
updateRowInT1(); //r.Partner = r2.Partner;
updateRowInT2(); //r2.Quantity = r2.Quantity - r.soldQuantity;
break;
}
}
}
This part of code best describes what I need to do.
Is there any way to do this in SQL (with user-defined functions).
Because of changes in second table I can't use update and join. Or I can?
Also, this is part of ETL process done by Pentaho Kettle. Is perhaps way to do this inside this tool.?
Thanks
Edit:
I have changed code above.
What I need to achieve?
Regular Sales by Partner.
What's wrong right now?
When some SKU is sold in retail shop, I can see SKU LAST Partner. But, company I work for is buying same SKU from more Partners.
Slowly Changing Dimension is not applicable because when we switch partner on SKU, there is still some quantity of that SKU on shelf.
Assumption:
FIFO - first In first Out.
So, for initial matching, I need to compare (in date order) both sales and buying and to decrement bought quantity.
You probably should be thinking in a more set oriented way.
Assuming I understand what you are trying to do properly, I would do this in two update statements:
-- Update table_1's Partner based on a row in table_2.
UPDATE table_1 r
SET Partner = r2.Partner
FROM table_2 r2
WHERE r2.key1 = r.key1
AND r2.key2 = r.key2;
-- Reduce the Quantity in table_2 based on table_1's soldQuantity
UPDATE table_2 r2
SET Quantity = r2.Quantity - r.soldQuantity
FROM table_1 r
WHERE r.key1 = r2.key1
AND r.key2 = r2.key2
AND r2.Quantity >= r.soldQuantity;
-- Both of these should be done in a transaction so it is all or none. Commit the work.
COMMIT;
You can see the SQLFiddle here.
I have a data set that lists the date and quantity of future stock of products. Occasionally our demand outstrips our future supply and we wind up with a negative future quantity. I need to factor that future negative quantity into previous supply so we don't compound the problem by overselling our supply.
In the following data set, I need to prepare for demand on 10-19 by applying the negative quantity up the chain until i'm left with a positive quantity:
"ID","SKU","DATE","SEASON","QUANTITY"
"1","001","2012-06-22","S12","1656"
"2","001","2012-07-13","F12","1986"
"3","001","2012-07-27","F12","-283"
"4","001","2012-08-17","F12","2718"
"5","001","2012-08-31","F12","-4019"
"6","001","2012-09-14","F12","7212"
"7","001","2012-09-21","F12","782"
"8","001","2012-09-28","F12","2073"
"9","001","2012-10-12","F12","1842"
"10","001","2012-10-19","F12","-12159"
I need to get it to this:
"ID","SKU","DATE","SEASON","QUANTITY"
"1","001","2012-06-22","S12","1656"
"2","001","2012-07-13","F12","152"
I have looked at using a while loop as well as an outer apply but cannot seem to find a way to do this yet. Any help would be much appreciated. This would need to work for sql server 2008 R2.
Here's another example:
"1","002","2012-07-13","S12","1980"
"2","002","2012-08-10","F12","-306"
"3","002","2012-09-07","F12","826"
Would become:
"1","002","2012-07-13","S12","1674"
"3","002","2012-09-07","F12","826"
You don't seem to get a lot of answers - so here's something if you won't get the right 'how-to do it in pure SQL'. Ignore this solution if there's anything SQLish - it's just a defensive coding, not elegant.
If you want to get a sum of all data with same season why deleting duplicate records - just get it outside, run a foreach loop, sum all data with same season value, update table with the right values and delete unnecessary entries. Here's one of the ways to do it (pseudocode):
productsArray = SELECT * FROM products
processed = array (associative)
foreach product in productsArray:
if product[season] not in processed:
processed[season] = product[quantity]
UPDATE products SET quantity = processed[season] WHERE id = product[id]
else:
processed[season] = processed[season] + product[quantity]
DELETE FROM products WHERE id = product[id]
Here is a CROSS APPLY - tested
SELECT b.ID,SKU,b.DATE,SEASON,QUANTITY
FROM (
SELECT SKU,SEASON, SUM(QUANTITY) AS QUANTITY
FROM T1
GROUP BY SKU,SEASON
) a
CROSS APPLY (
SELECT TOP 1 b.ID,b.Date FROM T1 b
WHERE a.SKU = b.SKU AND a.SEASON = b.SEASON
ORDER BY b.ID ASC
) b
ORDER BY ID ASC
HI ALL
I wish to update a row within my table from a row within that same table,
I have a table called INVENTORY. it stores PRICES for products.
I have SALES codes and I have STOCK codes which are related.
I wish to transfer all the PRICING from the SALES codes to the STOCK codes.
I wish to do something like this:
update INVENTORY
set PRICE = (SELECT PRICE WHERE CODE = "SALES CODE EQUIVALENT OF THE STOCK CODE IM IN")
WHERE
CODE = "SOME STOCK CODE"
a SALES CODE would look like this "U_12345", its STOCK code equivalent would look like "S_12345"
thanks
You're very close, you just need to specify which table you're selecting from as part of your sub-query...
update INVENTORY
set PRICE = (SELECT PRICE FROM your_table WHERE CODE = "SALES CODE EQUIVALENT OF THE STOCK CODE IM IN")
WHERE
CODE = "SOME STOCK CODE"
Even if "your_table" is INVENTORY, you still need to specify it in there.
The only time it gets 'tricky' is when your selecting from the same table that you're update, AND when you need a value from the updated record in the SELECT statement. In that case you need to differentiate between the two references, using an alias. For example...
update INVENTORY
set PRICE = (SELECT PRICE FROM INVENTORY AS [new_price] WHERE [new_price].CODE = INVENTORY.NEW_CODE)
WHERE
CODE = "SOME STOCK CODE"
UPDATE INVENTORY
SET PRICE = i_sales.PRICE
FROM INVENTORY, INVENTORY i_sales
WHERE INVENTORY.CODE LIKE 'S\_%'
AND i_sales.CODE = REPLACE(INVENTORY.Code, 'S', 'U')
This updates prices for all 'stock' records in INVENTORY with prices from the corresponding 'sales' records.
If you would prefer to update individual prices, change WHERE to something like this:
WHERE i_stock.CODE = 'S_12345'
or this:
WHERE i_stock.CODE IN ('S_12345', 'S_12346')
Note: The FROM syntax used is based on this doc page.