T-SQL Sum Case Confusion - sql

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

Related

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 Cast, Case and Count function

I am trying to count rows of email opens and divide it by the total email sends and convert this into decimal (so it shows percentage).
I am getting the error: "An error occurred while checking the query syntax. Errors: Incorrect syntax near ')'."
I have tried separating the code so I can get the count and case function separately to cast. Cast works without the count/case. Count/case also works independently, it just doesn't seem to work all together. Am I missing something here?
SELECT
SubscriberKey
,CAST(
((COUNT(CASE
WHEN PreviousMonth <= 1
AND SendType = 'Auto'
AND Opened = 1
THEN 1
ELSE NULLEND ))/
(COUNT(CASE
WHEN PreviousMonth <= 1
AND SendType = 'Auto')))
AS DECIMAL(18,4)) * 100 AS 'AverageOpen'
FROM Data
GROUP BY SubscriberKey
An error occurred while checking the query syntax. Errors: Incorrect syntax near ')'.
I would write this using SUM(CASE). Note two things:
The 1.0 so the division is not integers (which can be an issue in some databases.
No else in the denominator to avoid divide-by-zero
I also left out the cast():
SELECT SubscriberKey
(SUM(CASE WHEN PreviousMonth <= 1 AND
SendType = 'Auto'
Opened = 1
THEN 1.0 ELSE 0
END) /
SUM(CASE WHEN PreviousMonth <= 1 AND
SendType = 'Auto'
THEN 1 -- no else so no divide by 0
END)
) * 100 AverageOpen
FROM Data
GROUP BY SubscriberKey;
You code may be failing because of NULLEND is not recognized in SQL.
I think what you want to achieve here is to get the average of opened = 1 divided by all.
SELECT cast((t1.Opened/t1.OverAll) as decimal(18,4)) * 100.00 as 'AverageOpen'
FROM
(SELECT
SubscriberKey
, SUM(CASE WHEN PreviousMonth <= 1 AND SendType = 'Auto' AND Opened = 1 THEN 1 ELSE 0 END) Opened,
, SUM(CASE WHEN PreviousMonth <= 1 AND SendType = 'Auto' THEN 1 ELSE 0 END) OverAll
FROM Data
GROUP BY SubscriberKey) as t1

SQL Query SUM and Divide by Distinct Date Count

I assistance, I am looking for the sum of a data field and then want to divide it by the number of distinct dates in that field.
SUM(CASE WHEN dateResolved IS NOT NULL
THEN 1 ELSE 0
END) / DISTINCT(dateResolved) AvgPerDay
If there are 32 dates in dateResolved, with 5 distinct dates, I want it to return 6.4.
By default it does integer division you need :
SUM(CASE WHEN dateResolved IS NOT NULL
THEN 1 ELSE 0
END) * 1.0 / COUNT(DISTINCT dateResolved) AvgPerDay
However simply count would also work :
COUNT(dateResolved) * 1.0 / COUNT(DISTINCT dateResolved) AvgPerDay
COUNT(dateResolved) will ignore null values.
I would do this as:
SUM(CASE WHEN dateResolved IS NOT NULL
THEN 1.0 ELSE 0
END) / COUNT(DISTINCT dateResolved) as AvgPerDay
But this is more simply phrased as:
COUNT(dateResolved) * 1.0 / COUNT(DISTINCT dateResolved) as AvgPerDay

Why does the parenthesis make a different in this sql query

The objective:
Find the percentage of high elevation airports (elevation >= 2000) by
state from the airports table.
In the query, alias the percentage column as
percentage_high_elevation_airports.
Could someone explain why the following 2 SQL statements give different results:
Correct result:
SELECT state,
100.0 * sum(CASE WHEN elevation >= 2000 THEN 1 ELSE 0 END) / count(*) as percentage_high_elevation_airports
FROM airports
GROUP BY state;
sample result:
MS 0.0
MT 100.0
NC 11.1111111111111
ND 10.0
and wrong result:
select
state,
100.0 * (sum(case when elevation >= 2000 then 1 else 0 end)/count(*)) as percentage_high_elevation_airports
from airports
group by 1;
sample result:
MS 0.0
MT 100.0
NC 0.0
ND 0.0
Only difference is the additional placement of () around the sum.
I would write this as:
SELECT state,
AVG(CASE WHEN elevation >= 2000 THEN 100.0 ELSE 0 END) as percentage_high_elevation_airports
FROM airports
GROUP BY state;
The issue is integer arithmetic. Some databases do an integer division and return an integer. So, 1/2 is 0 rather than 0.5. Some databases also apply this to avg() (but even some that do integer division to numeric averages).
I should note that this is database-specific.
Your question is not about another/better solution to your query
but about the wrong results you get with the use of parentheses, right?
Because:
sum(case when elevation >= 2000 then 1 else 0 end)
results to an integer
and count(*) is by definition an integer.
The division between them is an integer division truncating any decimal digits.
So you get 0 instead of 0.5 or 0.05.
To avoid situations like this you can multiply by a real number like you do: 100.0 first and then divide.
Or you could do this:
sum(case when elevation >= 2000 then 1.0 else 0.0 end)
which results in a sum that is a floating point number.
In any case make sure that at least one of the operands of the division is a real number.
Try below - you need to change the placement of your parenthesis
select
state,
(100.0 * sum(case when elevation >= 2000 then 1 else 0 end))/count(*)) as percentage_high_elevation_airports
from airports
group by 1

Percent change returns wrong result

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)