SQL query issue with zero discount - sql

I am using the below query to get total amount after a discount.
My issue is when the discount is equal to zero, the total amount becomes zero.
How can I resolve this issue?
SELECT
CAST(SUM(Quantity * UnitPrice * (Discount / 100)) AS varchar(50))
FROM
Stock_Purchase_Details

simple case construct
unitPrice *
case when discount > 0 then (discount / 100)
else 1 end
That's for the code you posted. Normally, a discounted price is
unitPrice * ((100 - discount) / 100)

If you want final amount after discount, you should use
CAST(SUM(Quantity * UnitPrice * (1-(Discount/100)) AS VARCHAR(50))
This will give you the amount after discount. Your current formula gives you the amount discounted, not the amount after discount

Why not check to see if Discount/0 is 0 before doing that, and if it is zero, then don't include it? This can be done via case statements:
CASE
WHEN (Discount/100) = 0 then (logic)
ELSE (other logic)
END
Just one solution, as I am sure there are others.

Just by looking at your query, Discount means percentage discounted, not percent discount. In other words, per your SQL query, if Discount is 60%, it doesn't mean 60% off, but it's 40% off.
I'm assuming that's not what you want, so the correct query should be:
SELECT Cast(SUM(Quantity * UnitPrice * ((100-Discount)/100)) as varchar(50))
from Stock_Purchase_Details

Related

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)

sql multiplication don't show properly total

There is strange multiplication in the script.
SUM(CAST(PurchLine.[Amount Including VAT] AS decimal(10,2)))
OVER(PARTITION BY PurchLine.[Document No_])AS "TotalAmount"
Finding the Total Amount from above.
TotalAmount * TotalAmount * Discount AS PaymentAmount
Finding the discount and final Payment Amount from the above.
For example I have 24.80 * (24.80*0.015) = 24.42
Instead of that I receive 24.30.
Also for the discount 24.80*0.015 = 49.60 This is not correct again. The correct result would be 0.372
But the strange part this is not working only when TotalAmount is lower than 3 digits. When the Total amount is below 100, always the discount is not correct.
I'm not sure what do I have to make so it would work all the time.
The problem was that the this table with column Discount was imported into the sql server from excel file. For some reason the column Discount was not Decimal.
All the column contain numbers like 0.0015, 0.010 and so on...
When I change the column datatype to decimal(10.4) for Discount everything start working fine.
But here is still the question, why this work for number bigger than 100 and for less than 100 don't work?

Correct way to calculate prices including tax in foreign currencies

I'm trying to upgrade an application so that I can sell to multiple countries. I store all of my prices in the database in GBP excluding tax up to 4dp and I need to calculate the prices in the country's currency including tax.
Do I multiply the price by the exchange rate against the price excluding tax (option 1) or do I calculate the amount including tax and then multiple by the exchange rate (option 2)? I have also added an option 3 after looking at how OpenCart calculates it which is similar to option 2 but only ever rounds when displaying it. Here are the formula's for all 3 options:
Option 1:
Round((Price * Exchange Rate) / 100 * (100 + Tax Rate))
Option 2:
Round(Round(Price / 100 * (100 + Tax Rate)) * Exchange Rate)
Option 3:
Round((Price / 100 * (100 + Tax Rate)) * Exchange Rate)
For example say I have a product with a price of 89.99. If I wanted to display that in a currency with an exchange rate of 1.5 and a tax rate of 20%. Would I say:
Option 1:
Round((89.99 * 1.5) / 100 * (100 + 20)) = 161.98
Option 2:
Round(Round(89.99 / 100 * (100 + 20)) * 1.5) = 161.99
Option 3:
Round((89.99 / 100 * (100 + 20)) * 1.5) = 161.98
I've found that OpenCart always multiplies the unrounded figures by the exchange rate at the end. For example their formula for calculating the line total is:
Round((Price / 100 * (100 + Tax Rate)) * Quantity * Exchange Rate)
So if I was to order 3 of my product's it would give:
Round((89.99 / 100 * (100 + 20)) * 3 * 1.5) = 485.95
The problem I find doing it OpenCart's way is the user will see an item price (including tax) of 161.98 and a line total of 485.95. However if I say 161.98 * 3 I get 485.94, so it doesn't sum up correctly.
It's important I get this right as you can see I'll end up with penny issues. I'd appreciate it if someone could let me know which way is correct or suggest an alternative if none are right. Thanks
Since all variables are rounded except Exchange Rate, which I would expect to usually look something like this 1.3462, we can write a test like this:
// I'm guessing you need it in PHP
$price = 89.99;
$quantity = 1;
$tax = 20;
$tax = $tax/100.0 + 1;
// $tax = 1.2
$exchangeRate = 1.5;
$totalPrice = $price*$quantity*$tax; // Test #1
$totalPriceRounded = round($price*$quantity*$tax,2); // Test #2
echo $totalPrice.'<br/>'.$totalPriceRounded;
Which would have this output:
107.988 // Test #1 <--- This is amount that needs to be paid to you and Great Britain
107.99 // Test #2 <--- rounded
Now, it's obvious there is a difference in amount, so which to choose? Since you are charging an item from Great Britain, you expect to get paid the full amount you are asking for, in GBP, so lets rely on that factor. In the end, if I understood correctly, the tax the customer has to pay is tax to Great Britain.
Lets check the final prices in foreign currency:
$totalPrice = round($totalPrice * $exchangeRate,2);
$totalPriceRounded = round($totalPriceRounded * $exchangeRate,2);
echo $totalPrice.'<br/>'.$totalPriceRounded;
Which would have this output:
// Amount in foreign currency
161.98 // Test #1
161.99 // Test #2
With all that said, lets check which one of these would return you a value closest to 107.988 GBP when calculated back to GBP from foreign currency.
// To calculate the totalPrice back to price*tax*quantity in GBP
$totalPrice /= $exchangeRate;
$totalPriceRounded /= $exchangeRate;
echo $totalPrice.'<br/>'.$totalPriceRounded;
Output of which is:
// totalPrice in GBP currency
107.98666666667 // Test #1
107.99333333333 // Test #2
And when we divide by tax:
$totalPrice /= $tax;
$totalPriceRounded /= $tax;
echo $totalPrice.'<br/>'.$totalPriceRounded;
Output is:
// the amount you get in GBP currency
89.988888888889 // End result of Test #1
89.994444444444 // End result of Test #2
So as you can see, in this case, by using the bare amount of round($price*$quantity*$tax*$exchangeRate, 2) you are getting less, but by using round(round($price*$quantity*$tax,2)*$exchangeRate, 2) you get a little more which again, rounded both give the same value. In some other scenario the difference will likely be different from what we got here and might be the other way around.
CONCLUSION
If you have a fixed number of products each with fixed prices then you will be either loosing money (an insignificant amount) or earning more than you should (also an insignificant amount) over time. The outcome depends on the popularity and price of each product (i.e. will the round function round up or down), and on the way of calculation you chose. You could, depending on product popularity, manually adjust the prices of each product to minimize the loss/gain over time.
If you have products with random prices like lets say you are renting web servers and the price is $0.01/second. Then the expectation value for your loss/gain is close to zero. And the more purchases are made the closer to zero it gets. So you are not loosing anything here regardless of the approach. One time you win some one time you loose some.
In my opinion I would standardize it to round everything:
$price = 4.47;
$quantity = 1.2 // lets say liters
// Even round the price before applying tax
$totalPrice = round($price * $quantity, 2);
because if you are forced to show all the different stages of calculation then you will have to round every step.
But the most precise would be to use this as the least information is lost:
// Round once at end
$totalPrice = round($price*$quantity*$tax*$exchangeRate, 2);
In the end it all depends on how you set up your product prices or how your pricing works to be able to choose which method to go with. I'd say it doesn't really matter, I think every company simply chooses what suits them best.
Legally, some countries/cities/etc. have laws on how to calculate this, you should be looking at Great Britain laws to check on the valid procedure for your problem.
I can't tell you what the correct option is or even if there is one correct option. But from experience I can say, if there are multiple options to do one thing, make it configurable in your software. In this case you can easily use the strategy pattern and make the strategy for calculating prices configurable. Customers can choose how they want it calculated.
The correct solution depends on your business. When you sell items in different countries, you most likely have branches in those countries - and you need a net price in those country's currency. This results in the net price per item "translated" to the foreign currency, and this net price is then multiplied with the amount and multiplied with the tax factor/percentage).
The EU MOSS (which is charged when you offer services in other countries, or e.g. software as download) is somehow different. You can sell products with GBP pricing, but have to consider your consumer's local tax factor. See e.g. https://ec.europa.eu/taxation_customs/sites/taxation/files/resources/documents/taxation/vat/how_vat_works/telecom/one-stop-shop-guidelines_en.pdf
For MOSS, I didn't check in detail, but I expect that you then have a different formula, using your local GBP net price per item, multiply with amount, multiply with consumer's tax percentage. This tax amount, still in GBP, should then be multiplied with currency exchange rate, I'd expect.

SQL Server parameters and percentage increase

How would one use a parameter to increase orders on the orderdetails table by 10 percent?
I did something like: add parameter named IncPercent to the value of an order if the value of IncPercent is under 10%, or if IncPercent is 10% or over, add 10% to the value of an order for all orders in the
OrderDetails table utilising IF/ELSE.*/
Code that I have so far I'm kinda stuck
Create procedure [spAddPercentage]
#incPercent decimal(5,4)
as
update OrderDetails
set #incPercent = #incpercent * 1.10
.........
I cannot figure out how to use the if else statement in this code. Can anyone give me a better understanding or give me a example on what I should add for if/else?
Using an IF/ELSE here seems like a more complicated way to accomplish this. A case expression would be much simpler.
update OrderDetails
set Value = Value * (1 + case when #incPercent < .1 then .1 else #incPercent end)
Here is info on using IF ELSE
https://msdn.microsoft.com/en-gb/library/ms182717.aspx

SQL math syntax difficulty with division

Can't understand why I can't get the correct answer. I'm trying to calculate a net margin percentage but the divide portion is being ignored. Hopefully really simple one?
SUM(
(dbo.K3_TradeTeam_Sales2.TotalSales - dbo.K3_TradeTeam_SalesReturn3.TotalCredits)
ISNULL(dbo.K3_TradeTeam_Purch1.TotalPurchases, 0) /
dbo.K3_TradeTeam_Sales2.TotalSales
) AS NetMargin
To get a net margin you probably want an expression like this,
(
SUM(
dbo.K3_TradeTeam_Sales2.TotalSales
-
COALESCE(dbo.K3_TradeTeam_SalesReturn3.TotalCredits, 0.0)
-
COALESCE(dbo.K3_TradeTeam_Purch1.TotalPurchases, 0.0)
)
/
SUM(
dbo.K3_TradeTeam_Sales2.TotalSales
)
) AS NetMargin
However, without knowing your schema I couldn't say for sure. This would also fail miserable when you have 0.0 total sales.
I'm assuming that your want the sum of net profits for each realtion divided by the sum of the total revenue for each relation. This would give you the cumulative profit margin for all relationships.
The sql logic should work.
Are you sure that TotalPurchases is not null? Because this makes it look like the devide is ignored, but the devide just returns 0. So I'm doing minus zero!
examples:
select SUM((200 - 100) - ISNULL(100, 0) / 10) AS NetMargin --returns 90
select SUM((200 - 100) - ISNULL(null, 0) / 10) AS NetMargin --return 100
When I am having trouble getting a math formula to work, I change the select temporarily to simply see the values of each of the fields as well as the calculation. Then I can do the calualtion manually to see how I am getting the results I am getting which alwmost always points me to the problem.
select
dbo.K3_TradeTeam_Sales2.TotalSales,
dbo.K3_TradeTeam_SalesReturn3.TotalCredits,
ISNULL(dbo.K3_TradeTeam_Purch1.TotalPurchases, 0),
dbo.K3_TradeTeam_Sales2.TotalSales
From...
I also never do a division without a case statement to handle the divisor being 0 problem. Even if I think it can never happen, I have seen it burn people too often not to consider that something (including bad data entry) might make it happen in the future.