Percent change returns wrong result - sql

I've been at this for about 2 hours. I am trying to calculate the percentage change between two amounts. Here is the current code.
RejectedVsSubmittedSum = ((CASE WHEN COUNT(ClaimMain.ClaimNumber) > 0 THEN SUM(PCover.SumAssured) END
-ISNULL(SUM(CASE ClaimMain.CurrentStatus WHEN 25 THEN PCover.SumAssured END),0))
/NULLIF(SUM(CASE ClaimMain.CurrentStatus WHEN 25 THEN PCover.SumAssured END),0))
* 100
This line returns 225000.
CASE WHEN COUNT(ClaimMain.ClaimNumber) > 0 THEN SUM(PCover.SumAssured) END
This line returns 25000.
ISNULL(SUM(CASE ClaimMain.CurrentStatus WHEN 25 THEN PCover.SumAssured END),0)
The division.
NULLIF(SUM(CASE ClaimMain.CurrentStatus WHEN 25 THEN PCover.SumAssured END),0)
Then I times by 100.
So 225000 - 25000 / 25000 * 100 returns 800. This is what I'm returning, but based on this site http://www.percent-change.com/index.php?y1=225000&y2=25000, my result is wrong and I should be returning -88.88888888 %.
I don't have any real experience in doing these calculations in SQL so I presume the website is correct. Can anybody see if I am actually doing anything wrong?
I've already asked this Calculate percentage between two values, but now I am using a different set of numbers, I'm now using amounts of money and not just counts. I've tried to go with the same logic (because it made sense to do so) but it seems like I'm returning the wrong result.

According to the formula ((y2 - y1) / y1)*100, your query should be like this.
RejectedVsSubmittedSum = ( ( (ISNULL(SUM(CASE ClaimMain.CurrentStatus WHEN 25 THEN PCover.SumAssured END),0) )
- (CASE WHEN COUNT(ClaimMain.ClaimNumber) > 0 THEN SUM(PCover.SumAssured) END) )
/ (CASE WHEN COUNT(ClaimMain.ClaimNumber) > 0 THEN SUM(PCover.SumAssured) END) ) * 100
y1: CASE WHEN COUNT(ClaimMain.ClaimNumber) > 0 THEN SUM(PCover.SumAssured) END
y2: ISNULL(SUM(CASE ClaimMain.CurrentStatus WHEN 25 THEN PCover.SumAssured END),0)

Related

SQL case operation

Im fairly new with sql, and been trying to solve a problem where you have a table information about orders. In this case, Im trying to use the case operation to get a monthly report on orders, so I should have a column which states the year,another one which states the month, and then I should have columns for days 1-20,21-22,23-24 and above 25. Im trying to use the case operation to get the amount of orders that happened on those days.
I tried the following query :
SELECT
DATEPART(YEAR,date) AS year,DATEPART(MONTH,date) AS month,
COUNT(CASE WHEN DATEPART(DAY,date) BETWEEN 1 AND 20 THEN order ELSE 0 END) AS D1_D20,
COUNT(CASE WHEN DATEPART(DAY,date) BETWEEN 21 AND 22 THEN order ELSE 0 END) AS D21_D22,
COUNT(CASE WHEN DATEPART(DAY,date) BETWEEN 23 AND 24 THEN order ELSE 0 END) AS D23_D24,
COUNT(CASE WHEN DATEPART(DAY,date) > 25 THEN order ELSE 0 END) AS D25_END
FROM ORDERS
GROUP BY DATEPART(YEAR,date),DATEPART(MONTH,date)
Obviously the problem with that query is that, now I just get the total number of orders for each of the days, I know I should count the orders, but dont know the syntax. Help would be greatly appreciated!
Use SUM():
SELECT
DATEPART(YEAR, date) AS year, DATEPART(MONTH, date) AS month,
SUM(CASE WHEN DATEPART(DAY,date) BETWEEN 1 AND 20 THEN 1 ELSE 0 END) AS D1_D20,
SUM(CASE WHEN DATEPART(DAY,date) BETWEEN 21 AND 22 THEN 1 ELSE 0 END) AS D21_D22,
SUM(CASE WHEN DATEPART(DAY,date) BETWEEN 23 AND 24 THEN 1 ELSE 0 END) AS D23_D24,
SUM(CASE WHEN DATEPART(DAY,date) > 25 THEN 1 ELSE 0 END) AS D25_END
FROM ORDERS
GROUP BY DATEPART(YEAR, date), DATEPART(MONTH, date);
I would recommend using the functions DAY(), YEAR(), and MONTH() because they are simpler to type.
By the way, you can use COUNT() if you remove the ELSE clause. Your particular problem is that COUNT(0) = COUNT(1) because COUNT() counts non-NULL values. I prefer SUM() because it is more intuitive in this respect.

SELECT data grouped by WEEK in SQL

I have a working query (ORACLE SQL) that gives me gallons grouped by store number, with gallons summed by type and a percentage column as well. Each store number has a different conversion date from which I sum up the data -
SELECT StoreNbr,
SUM(CASE WHEN(ClrntSys IN ('844', '84448')) THEN Gallons ELSE 0 END) AS Gallons_844,
SUM(CASE WHEN(ClrntSys ='GIC') THEN Gallons ELSE 0 END) AS Gallons_GIC,
SUM(CASE WHEN(ClrntSys IN ('844', '84448', 'GIC')) THEN Gallons ELSE 0 END) AS Total_Gallons,
CONCAT(CAST((SUM(CASE WHEN(ClrntSys ='GIC') THEN Gallons ELSE 0 END) /
SUM(CASE WHEN(ClrntSys IN ('844', '84448', 'GIC')) THEN Gallons ELSE 0 END)) AS DECIMAL (5,2)) * 100, '%') AS Percent_GIC
FROM MQ_CDS_NETTRAN
WHERE ClrntSys IN ('844', '84448', 'GIC')
AND ((CostCenter = '701104' AND LastTranDate >= DATE '2020-03-10')
OR (CostCenter = '701109' AND LastTranDate >= DATE '2020-03-04')
OR (CostCenter = '701257' AND LastTranDate >= DATE '2020-03-12'))
GROUP BY StoreNbr
ORDER BY StoreNbr;
I now need to also sum it up by week, with Sunday being the first day of each week, but I'm having trouble understanding how DATEPART works. Just so I could get a better idea, I tried only to sum up the data for last week using DATEPART examples I'm seeing online, but this doesn't work. It's giving me "invalid identifier DATEPART". -
SELECT DATEPART(week, 5/17/20) AS weekTotal,
StoreNbr,
SUM(CASE WHEN(ClrntSys IN ('844', '84448')) THEN Gallons ELSE 0 END) AS Gallons_844,
SUM(CASE WHEN(ClrntSys ='GIC') THEN Gallons ELSE 0 END) AS Gallons_GIC,
SUM(CASE WHEN(ClrntSys IN ('844', '84448', 'GIC')) THEN Gallons ELSE 0 END) AS Total_Gallons,
CONCAT(CAST((SUM(CASE WHEN(ClrntSys ='GIC') THEN Gallons ELSE 0 END) /
SUM(CASE WHEN(ClrntSys IN ('844', '84448', 'GIC')) THEN Gallons ELSE 0 END)) AS DECIMAL (5,2)) * 100, '%') AS Percent_GIC
FROM MQ_CDS_NETTRAN
WHERE ((CostCenter = '701104' AND LastTranDate >= DATE '2020-03-10')
OR (CostCenter = '701109' AND LastTranDate >= DATE '2020-03-04')
OR (CostCenter = '701257' AND LastTranDate >= DATE '2020-03-12'))
GROUP BY DATEPART(week, 5/17/20), StoreNbr
ORDER BY StoreNbr;
What I really need, however, is each week's data (with Sunday being the beginning of each week) summed up separately going back to each store's conversion date. Is it possible to do that? Is there something else besides DATEPART that would work better?
Sorry - just noticed that you said Oracle SQL, and my first answer was for SQL Server! The reason you are getting an error is that DATEPART is not an Oracle function. Instead, you can simply do math on the dates, using a known sunday (prior to a known first date in the DB table) as an anchor date:
SELECT
'30-DEC-2018' as "Known Sunday,
trunc((sysdate - to_date('30-DEC-2018')) / 7) as "Week Num",
to_date('30-DEC-2018')
+ (trunc((sysdate - to_date('30-DEC-2018')) / 7) * 7)"
FROM
dual

SQL using SUM in CASE in SUM

I had this query select
sum(CASE WHEN kpi.average >= temp.average THEN 1 ELSE 0 END) AS recordOrder,
which worked fine, but I had to change it to this
sum(CASE WHEN sum(kpi.averageUse) / sum(kpi.averageTotal) >= temp.average THEN 1 ELSE 0 END) AS recordOrder,
These queries have to get number of rows, where some value (average) is greater than average from TEMP table. But in the second query I have more accurate data (weighted average).
but I am getting error
1111 invalid use of group function
Any ideas how to write SUM in CASE in SUM?
Thanks!
This code is just non-sensical because you have nested sum functions:
sum(CASE WHEN sum(kpi.averageUse) / sum(kpi.averageTotal) >= temp.average THEN 1 ELSE 0 END) AS recordOrder,
Without seeing your larger query, it is not possible to know what you really intend. But I would speculate that you don't want the internal sum()s:
sum(CASE WHEN (skpi.averageUse / kpi.averageTotal) >= temp.average THEN 1 ELSE 0 END) AS recordOrder,

SQL, querying sum of positive results, absolute value

I have the following query which returns a total dollar amount.
select sum(cast(dollars as dec)) from financials
This includes positive and negative values.
I would like 2 separate things:
How can I just query the positive dollar amounts? ie. I have 3 records, 10 , -5 , 10. result would be 20.
I want an absolute value as a sum. ie. I have 3 records, 10, -5, 10. the result would be 25.
thanks.
FOR 1) Use conditional SUM()
SELECT SUM( CASE WHEN dollars > 0 then dollars ELSE 0 END) as positive_sum,
SUM( CASE WHEN dollars < 0 then dollars ELSE 0 END) as negative_sum
FROM financials
FOR 2) use ABS()
SELECT SUM( ABS( dollars ) )
FROM financials
Please try below queries. Thanks.
1) select sum(cast(dollars as dec))
from financials
where dollars > 0;
2) select sum(cast(abs(dollars) as dec))
from financials;
You have two queries.solutions are as follows
1.
select sum(dollars) from financials
2.
select sum((case when dollars>0 then dollars end))+sum((case when dollars<0 then -1*dollars end)) from financials

T-SQL Sum Case Confusion

I am currently doing a SUM CASE to workout a percentage, however the entire string returns zero's or ones (integers) but I don't know why. I have written the SQL in parts to break it out and ensure the underlying data is correct which it is, however when I add the last part on to do the percentage it fails. Am I missing something?
SELECT
SUPPLIERCODE,
(SUM(CASE WHEN ISNULL(DATESUBMITTED,0) - ISNULL(FAILDATE,0) <15 THEN 1 ELSE 0 END)) AS ACCEPTABLE,
COUNT(ID) AS TOTALSUBMITTED,
(SUM(CASE WHEN ISNULL(DATESUBMITTED,0) - ISNULL(FAILDATE,0) <15 THEN 1 ELSE 0 END)/COUNT(ID))
FROM SUPPLIERDATA
GROUP BY SUPPLIERCODE
For example here's some of the data returned:
SUPPLIERCODE ACCEPTABLE TOTALSUBMITTED Column1
HBFDE2 1018 1045 0
DTETY1 4 4 1
SWYTR2 579 736 0
VFTEQ3 2104 2438 0
I know I could leave the other columns and use an excel calculation but I'd rather not... Any help would be well received. Thanks
SELECT
SUPPLIERCODE,
(SUM(CASE WHEN ISNULL(DATESUBMITTED,0) - ISNULL(FAILDATE,0) <15 THEN 1 ELSE 0 END)) AS ACCEPTABLE,
COUNT(ID) AS TOTALSUBMITTED,
(SUM(CASE WHEN ISNULL(DATESUBMITTED,0) - ISNULL(FAILDATE,0) <15 THEN 1 ELSE 0 END)*1.0/COUNT(ID))
FROM SUPPLIERDATA
GROUP BY SUPPLIERCODE
You need convert your result to float. It can be easy done by multiply on 1.0
This is due to the fact that SQL Server is treating your values as INTs for the purpose of division.
Try the following and you will see the answer 0:
PRINT 1018 / 1045
In order to allow your operation to work correctly, you need to convert your values to FLOATs, like so:
PRINT CAST(1018 AS FLOAT) / 1045
This will produce the answer 0.974163 as expected.
A simple change to your statement to introduce a cast to FLOAT will sort your problem:
SELECT
SUPPLIERCODE,
(SUM(CASE WHEN ISNULL(DATESUBMITTED,0) - ISNULL(FAILDATE,0) <15 THEN 1 ELSE 0 END)) AS ACCEPTABLE,
COUNT(ID) AS TOTALSUBMITTED,
(CAST(SUM(CASE WHEN ISNULL(DATESUBMITTED,0) - ISNULL(FAILDATE,0) <15 THEN 1 ELSE 0 END) AS FLOAT) / COUNT(ID))
FROM SUPPLIERDATA
GROUP BY SUPPLIERCODE
All you have to do is avoid integer division by giving your database engine a hint.
In SQL Server, you would use:
SELECT
SUPPLIERCODE,
(SUM(CASE WHEN ISNULL(DATESUBMITTED, 0) - ISNULL(FAILDATE, 0) < 15 THEN 1 ELSE 0 END)) AS ACCEPTABLE,
COUNT(ID) AS TOTALSUBMITTED,
(SUM(CASE WHEN ISNULL(DATESUBMITTED, 0) - ISNULL(FAILDATE, 0) < 15 THEN 1 ELSE 0 END) / (COUNT(ID) * 1.0))
FROM
SUPPLIERDATA
GROUP BY
SUPPLIERCODE