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

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.

Related

Calculate theoretically available quantity of a BOM item

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

CASE expression returns wrong values during percentage calculation

I am currently working on a supermarket database design where I have to have retrieve the price of the product after discount.
There are 2 types of discount: Direct Discount, Quantity Based Discount. The product will either have percentage discount (eg: 10% off) or amount/cash discount (eg: $5 off)
Currently, my code only works for quantity based discount but not the direct discount (percentage discount) where it will return a wrong value.
select id, product_name, unitPrice,Product.discount_cd,
discount_percentange as 'Discount Percentage' ,
discount_amount as 'Discount Amount',
Promotion_Type.quantity,
case when Product.discount_cd NOT LIKE '%DD' AND discount_percentange IS NOT NULL
THEN (unitPrice*ISNULL(discount_percentange,1))*ISNULL(quantity,1)
when (Promotion_Type.discount_cd NOT LIKE '%QB' AND Promotion_Type.discount_percentange IS NOT NULL)
THEN (unitPrice-(unitPrice*discount_percentange))
ELSE (unitPrice*ISNULL(quantity,1))-(unitPrice*ISNULL(discount_percentange,0))-(ISNULL(discount_amount,0))
END AS reduce
from Product
LEFT JOIN Promotion_Type ON Product.discount_cd=Promotion_Type.discount_cd
Based on the picture attached, reduced price for product P001 and P005 is wrong.
Can I know where is the error? The screenshot of the database table output
database product table
I see multiple issues with your CASE statement.
First, I think you are misusing the % wildcard. It represents any number of any characters at the place it is located. For example, '%DD' means anything as long as the last two characters are 'DD'. Adding the NOT just flips it. Therefore, Product.discount_cd NOT LIKE '%DD' will evaluate true as long as the Product.discount_cd does not end in 'DD', which is all of the codes. When you add in the AND discount_percentage IS NOT NULL, the result is, any record that has a discount_percentage will return with the first THEN statement. This includes P001 and P005.
Second, I think you are misusing the ISNULL() function. It's unnecessary to use it on discount_percentageas you have IS NOT NULL as a criterion. Also, if quantity refers to the product quantity, I do not think you should return a 1 when quantity is null.
Presuming that "DD" stands for "Direct Discount", I don't understand why you have records with a "DD" code and no discount_percentage. That being said, I think the below revised CASE statement will meet your needs.
CASE
WHEN
Product.discount_cd LIKE 'DD%' --Any code beginning with 'DD'
AND discount_percentage IS NOT NULL --Must have discount percentage
THEN (unitPrice * ISNULL(quantity,0)) - (unitPrice * ISNULL(quantity,0) * discount_percentage)
WHEN
Promotion_Type.discount_cd LIKE 'QB%' --Any code beginning with 'QB'
AND discount_amount IS NOT NULL --Must have discount amount
THEN unitPrice * ISNULL(quantity,0) - discount_amount
ELSE 0 --No valid discount
END AS reduce
Check this first condition,
case when Product.discount_cd NOT LIKE '%DD' AND discount_percentange IS NOT NULL
THEN (unitPrice*ISNULL(discount_percentange,1))*ISNULL(quantity,1)
The unit discount amount should be deducted from unitPrice.
case when Product.discount_cd NOT LIKE '%DD' AND discount_percentange IS NOT NULL
THEN (unitPrice-(unitPrice*ISNULL(discount_percentange,1)))*ISNULL(quantity,1)

Get the product of two values from two different tables

If anyone can help me figure out where I am going wrong with this SQL that would be great. Please see my attempt to answer it below. I have answer how I think it should be answered but I am very confused by the exam advice below, which says I should use a SUM function? I have googled this and I do not see how a SUM function can help here when I need get the product of two values in this case. Or am I missing something major?
Question: TotalValue is a column in Order relation that contains derived data representing total value (amount) of each order. Write a SQL SELECT statement that computes a value for this column.
My answer:
SELECT Product.ProductPrice * OrderLine.QuantityOrdered AS Total_Value
FROM Product,
OrderLine
GROUP BY Product;
Advice from exam paper:
This is a straightforward question. Tip: you need to use the SUM function. Also, note that you can take the sum of various records set using the GROUP BY clause.
Ok your question became a lot clearer once I clicked on the the hyperlink (blue text).
Each order is going to be made up of a quantity of 1 or more products.
So there could be 3 Product A and 5 Product B etc.
So you have to get the total for each product which is your Price * Quantity, but then you need to add them all together which is where the SUM comes in.
Example:
3 * ProductA Price (e.g. €5) = 15
5 * ProductB Price (e.g. €4) = 20
Total Value = 35
So you need to use the Product, Order and OrderLine tables.
Something like (I haven't tested it):
SELECT SUM(Product.ProductPrice * OrderLine.QuantityOrdered) FROM Product, Order, OrderLine
WHERE Order.OrderID = OrderLine.OrderID
AND Product.ProductID = OrerLine.ProductID
GROUP BY Order.OrderID
This should return rows containing the totalValue for each order - the GROUP BY clause causes the SUM to SUM over each group - not the entire rows.
For a single order you would need add (before the GROUP BY) "AND Order.OrderID = XXXXX" where XXXXX is the actual orders OrderId.

SQL: Calculate Percentage in new column using another column

I found it hard to describe what I wanted to do in the title, but I will be more specific here.
I have a reasonably long query:
SELECT
/*Amount earned with validation to remove outlying figures*/
Case When SUM(t2.[ActualSalesValue])>=0.01 OR SUM(t2.[ActualSalesValue])<0 Then SUM(t2.[ActualSalesValue]) ELSE 0 END AS 'Amount',
/*Profit earned (is already calculated then input into db, this just pulls that figure*/
SUM(t2.[Profit]) AS 'Profit',
/*Product Type - pulls the product type so that we can sort by product*/
t1.[ucIIProductType] AS 'Product Type',
/*Profit Percentage - This is to calculate the percentage of profit based on the sales price which uses 2 different columns - Case ensures that there are no wild values appearing in the reports as previously experienced*/
Case When SUM(t2.[ActualSalesValue])>=0.01 OR SUM(t2.[ActualSalesValue])<0 THEN (SUM(t2.[Profit])/SUM(t2.[ActualSalesValue])) ELSE 0 END AS 'Profit Percentage',
/*Percentage of Turnover*/
*SUM(t2.[ActualSalesValue])/(Select SUM(t2.[ActualSalesValue]) OVER() FROM [_bvSTTransactionsFull]) AS 'PoT'
/*The join is connect the product type with the profit and the amount*/
FROM [dbo].[StkItem] AS t1
INNER JOIN [dbo].[_bvSTTransactionsFull] AS t2
/*There attirbutes are the links between the tables*/
ON t1.[StockLink]=t2.[AccountLink]
WHERE t2.[TxDate] BETWEEN '1/Aug/2014' AND '31/Aug/2014' AND ISNUMERIC(t2.[Account]) = 1
Group By t1.[ucIIProductType]
The 'Percentage of Turnover' part I am having trouble with - I am trying to calculate the percentage of the Amount based on the total amount - using the same column. So eg: I want to take the Amount value in row 1, then divide it by the total amount of the entire column and then have that value listed in a new column. But I keep getting errors or I Keep getting 1 (because it wants to divide the value by the same value. CAN anyone please advise me on proper syntax for solving this:
/*Percentage of Turnover*/
*SUM(t2.[ActualSalesValue])/(Select SUM(t2.[ActualSalesValue]) OVER() FROM [_bvSTTransactionsFull]) AS 'PoT'
I think you want one of the following:
SUM(t2.[ActualSalesValue])/(Select SUM(t.[ActualSalesValue]) FROM [_bvSTTransactionsFull] t) AS PoT
or:
SUM(t2.[ActualSalesValue])/(SUM(SUM(t2.[ActualSalesValue])) OVER() ) AS PoT
Note: you should use single quotes only for string and date constants, not for column and table names. If you need to escape names, use square braces.

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