Calculate theoretically available quantity of a BOM item - sql

For a project I'm working on, I need to be able to communicate the quantity available to 'make' for a BOM item based on its contents. I won't go in-depth as to how this will be communicated, the base is in the SQL query.
The idea is fairly simple;
a BOM (Bill Of Material, indicating that it requires to be created) item (let's call this BOM1) has 1 or more stockitems linked to it. Having a quantity of 1 or higher. In this example let's take ITEM1 (3 units) ITEM2 (2 units) and ITEM3(5 units). Naturally, all of this is stored in a single table for referencing;
Secondary to that, there's the quantity in stock for each part within that BOM. this is stored in a 'bin content' table, example as below;
The sum of the stock, per item, is then summarised as below;
Now, based on the 'contribution' of each item to the BOM item, you can calculate the maximum available number to create;
in this scenario, based on ITEM3, I can create a maximum of 8 of item BOM1 as this has the lowest contribution (for lack of a better word I guess). Let's assume that parts can only be used once for a BOM item.
I can create a query for a single BOM item using a TOP 1 and ORDER BY ASC statement, the problem is that I have multiple BOM items, each having its own parts with multiple bin locations;
select TOP 1
BOM_ITEM.ITEM_NO
, (SUM(BIN_CONTENT.QTY) / BOM_ITEM.PART_ITEM_QTY) as AVAIL_TO_MAKE
from BOM_ITEM
JOIN BIN_CONTENT
ON BOM_ITEM.PART_ITEM_NO = BIN_CONTENT.ITEM_NO
WHERE BOM_ITEM.ITEM_NO = 'BOM1'
GROUP BY
BOM_ITEM.ITEM_NO
ORDER BY AVAIL_TO_MAKE ASC
So, based on the BOM item, I want to retrieve only the part item qty with the lowest 'contribution' so to communicate the theoretically available quantity to make, I just can't figure it out though.
any suggestions would be greatly appreciated!

The below query computes for each BOM item, how many items can be created given the available stock.
The query uses subquery to compute the stock across all bins. The main query groups by BOM item. For each BOM item, the minimum available to make is used. Additionally, the floor function is used to round down to an integer value.
WITH STOCK
USING (
SELECT ITEM_NO, SUM(QTY) AS QTY
FROM BIN_CONTENT
GROUP BY ITEM_NO
)
SELECT BOM_ITEM.ITEM_NO AS BOM_ITEM_NO,
FLOOR(MIN(STOCK.QTY / BOM_ITEM.PART_ITEM_QTY)) AS AVAIL_TO_MAKE
FROM BOM_ITEM
JOIN STOCK ON STOCK.ITEM_NO = BOM_ITEM.ITEM_NO
GROUP BY BOM_ITEM.ITEM_NO

Related

single CASE for multiple columns data

Item with quantity and price are queried from SQL server for Excel and Crystal Report. The quantity and price are bulk quantity (pounds). I need to convert it to bag quantity and bag price. Pounds per bag data is not in SQL server and it is different on each item. My item is around 20 only. I cannot create permanent or temporary table to store pounds per bag data in SQL Server. I can use CASE in SQL to calculate bag quantity and price. But, it needs two CASEs. How can I use one CASE or other method which can simplify the SQL and keep it simple to maintain? My current SQL.
SELECT Item, Quantity, Price,
CASE item
WHEN ‘Item1’ THEN Quantity/32
WHEN ‘Item2’ THEN Quantity/33
…
ELSE Quantity
END AS QtyPerBag,
CASE item
WHEN ‘Item1’ THEN Price*32
WHEN ‘Item2’ THEN Quantity*33
…
ELSE Price
END AS PricePerBag
FROM MasterTable
DhruvJoshi's approach is a good approach. Using the VALUES() constructor, it is even simpler:
SELECT mt.Item, mt.Quantity, mt.Price,
mt.Quantity/factors.Factor AS QtyPerBag,
Price * Factors.factor AS PricePerBag
FROM MasterTable mt LEFT JOIN
(VALUES ('Item1', 32), ('Item2', 33)
) factors(item, factor)
ON factors.item = mt.item;
Note: If you quantity is stored as an integer, then you should use decimal points for the factors (unless you want integer division).
As already pointed out in comments you should consider using table/set approach.
One way if you want to do that inside of a query is like below:
SELECT Item, Quantity, Price, Quantity/Factor AS QtyPerBag,
Price * Factor AS PricePerBag
FROM MasterTable LEFT JOIN
(
SELECT 'Item1' as Item, '32' as Factor
UNION
SELECT 'Item2' as Item, '33' as Factor
-- and so on ...
) T
ON T.item=masterTable.item

How do I perform math in SQL query on certain conditions?

I have a few tables I am querying, Item movement, and price. There are three price levels, regular price, reduced price, and sale price. I am attempting to get a markdown (price that item sold at when on sale minus either the regular or reduced price). My item movement table contains only the price the unit sold at and the price type of that sale. I am currently selecting only the items that sold on the sale price type. Next I have to find out whether the item was on a regular or reduced price, which I determine by looking at my price table. The price table has my regular price and reduced price and if the reduced price is null then it is not currently reduced.
How do I tell SQL that I want a column named "markdown" that is essentially (IF price.tprprice not null AND price.tprenddate > #StartDate give me column (price.baseprice - price.tprprice) * itemmovement.qtysold AS markdown ELSE give me column (price.baseprice - itemmovement.price) * itemmovement.qtysold AS markdown)
I need to return the result of each calculation performed on each row into the same column titled Markdown.
Can anyone tell me how this query should be structured?
case when price.tprprice is not null AND price.tprenddate > #StartDate
then (price.baseprice - price.tprprice) * itemmovement.qtysold
else (price.baseprice - itemmovement.price) * itemmovement.qtysold
end as markdown
You would do it with a case statement which works in most databases.

Finding the cheapest shop which has all the requested list items

I am currently trying to use pure T-SQL with no additional work done using C# to find the cheapest store match to a list of products.
Finding the cheapest match works well, but my problem is that the found matches (the stores) do not necessarily have all the items in the list.
The tables necessary for this operation are:
Supermarkets - All available supermarkets.
ListItems - A table connecting item lists and products.
AvailProducts - A table that links between a product and a supermarket. If a row does not exist for a certain product ID and supermarket ID, then it means the supermarket does not have this product at all. This is the table which holds the Price for the product.
My current testing SQL statement is supposed to return up to 5 supermarkets which have the wanted products ordered from the cheapest to the most expensive sum, and it looks like this:
SELECT TOP 5 AvailProducts.[SuperID], SUM(AvailProducts.[Price]) AS "Price"
FROM AvailProducts, ListItems, Supermarkets
WHERE ListItems.[ListID]=3
AND AvailProducts.[ProductID]=ListItems.[ProductID]
AND AvailProducts.[SuperID]=Supermarkets.[ID]
AND (SELECT COUNT(*) FROM AvailProducts, ListItems WHERE AvailProducts.[ProductID]=ListItems.[ProductID] AND ListItems.[ListID]=3 AND AvailProducts.[SuperID]=)=(SELECT COUNT(*) FROM ListItems WHERE [ListID]=3)
GROUP BY AvailProducts.[SuperID]
ORDER BY SUM(AvailProducts.[Price])
The third line from the bottom is supposed to count the number of list items that are available in the supermarket and only return the supermarket's ID if the number of list items and the number of available items in this supermarket equal.
However, this does not work, because I cannot specify the current super market's ID in this statement.

How to calculate new value for field in Access

I've got a few problems with a database I have created.
I want to calculate a Total Price (Sandwich Quantity multiplied by Sandwich Price). I had it working before, but I had to delete Sandwich Price from the OrderDetailsT table of which it was originally in. I'm now having issues with this calculation, as I cannot make a calculation in the OrderDetailsT table (Sandwich Price isn't there).
How can I apply the Discount to the Total Price if the Total Price is more than $50 for instance? After the Discount has been applied to the Total Price field, I would also like to store it in the NewPriceAfterDiscount field.
Here is an image detailing my situation:
You have multiple questions in one:
But, first of all. As the image shows, why do you have a left join between OrderDetails an Sandwich? In a order calculation you don't need not ordered sandwiches.
To total price calculation:
Add a new column to the query grid (assuming discount is a percentaje stored has a number between 0 and 1):
[SandwichT].[SandwichPrice] * [OrderDetailT].[SandwichQuantity] * [OrderDetailT].[Discount]
To store total price: you can use the above formula, but using a update query.
If you plan to show the prices in a form or in a report:
you can do de calculations on the fly (and don't store the total
price)
or you should update the total price un one query and then build another
query as datasource of the form/report.
another posibility (my recomendation) is to store the total in the input form

Products with only one available colour in stock - SQL query

I have a table that lists thousands of products. A product can be either Standard (123450.000.000), one colour (123456.BLA.000), one size (123456.000.LAR) or both colour and size (123456.BLA.LAR).
A product can have multiple colours (123456.BLA.000, 123456.YEL.OOO etc etc). I am trying to do a query that brings back a product that has multiple colours but only one colour in stock i.e. ProductQTY = 1 and the remaining colours are out of stock.
All I have been able to come up with is the query below but this just brings back all 'variant' products that have 1 in stock. What do I have to add or change to make it bring back results whereby a product has different colours but only ONE of those colours are in stock and the remaining are out of stock? Do I need to do a UNION?
select *
from Product
where productcode NOT LIKE ('%000.000')
AND ProductQTY = '1'
First off, that's a terrible structure. Store color and size information in separate tables, don't make them part of one massive variable.
Second, you want to do a query that selects Product IDs (1-6, looks like) that have a count > 1 with color present and the sum of their quantities is 1 exactly (according to your question - if that one record could have a qty>1 and still be okay, this is a little more complicated).
select * from product where substr(product,1,6) in (
select substr(product,1,6) from product
where not (product like '%.000.%')
group by 1
having count(1) > 1
and sum(ProductQTY)=1
)
The question would be much easier if you would split up the properties in different columns. But you could do that in a query aswell:
select code from
(select substring(productcode,-3) as size,
substring(productcode,-7,3) as colour,
substring(productcode,0,len(prodcutcode)-7) as code
from product) t
group by code
having sum(productQTY) = 1
//or count(*) = 1 to get all unique ones