Subract one aggregate value from another - sql-server

I'm writing a query to aggregate bookings for an event, and to then split the total figure into two categories: a count of those people with an application, and a count of those without an application.
Calculating the total booking figure and the number of applicants is no problem - the code I'm using is as follows:
SELECT [EVENTMODULE].[DESCRIPTION] as 'Event', cast([EVENTMODULE].[STARTDATE] as date) as 'Event Date',
SUM (case when [EVENTPLACE].[STATUS] IN ('Accepted','Attended') then 1 else 0 end) 'Total Bookings',
SUM (case when [EVENTPLACE].[STATUS] IN ('Accepted','Attended') AND [COURSEPLACE].[TYPE] = 'Application' then 1 else 0 end) 'Current Applicants' ...
However, I'm having problems with calculating the count of people that do not have an application (i.e. they have no application record associated with their account). I've tried using a NOT EXISTS statement, but discovered that this won't work within an aggregate statement.
So, what I'm instead trying to do is simply subtract the 'Number of Applicants' from the 'Total Bookings' figure, as this will leave me with a count of the number of non-applicants.
I've tried to simply subtract the above two outputs using the line of code below:
SUM ('Total Bookings' - 'Current Applicants') 'Non-Applicants'
But this gives me the error:
"Msg 8117, Level 16, State 1, Line 4
Operand data type varchar is invalid for subtract operator."
I'm presuming I need to get the earlier output to cast as an Integer - please can anyone help me with the syntax?

You can't use column aliases from your calculations directly in the same query, you could use your current SELECT as a derived table, or a CTE, or simply derive your new calculation. Also, you should avoid using single quotes for table aliases, instead use []:
SELECT [EVENTMODULE].[DESCRIPTION] as [Event],
CAST([EVENTMODULE].[STARTDATE] as DATE) as [Event Date],
SUM(CASE WHEN [EVENTPLACE].[STATUS] IN ('Accepted','Attended') THEN 1 ELSE 0 END) [Total Bookings],
SUM(CASE WHEN [EVENTPLACE].[STATUS] IN ('Accepted','Attended') AND [COURSEPLACE].[TYPE] = 'Application' THEN 1 ELSE 0 END) [Current Applicants],
SUM(CASE WHEN [EVENTPLACE].[STATUS] IN ('Accepted','Attended') AND ISNULL([COURSEPLACE].[TYPE],'') <> 'Application' THEN 1 ELSE 0 END) [Non-Applicants]
...

Use Square Brackets to escape the space in column names. Single quotes will make it as string constant
select SUM ([Total Bookings] - [Current Applicants]) 'Non-Applicants'
from
(
SELECT [EVENTMODULE].[DESCRIPTION] as 'Event', cast([EVENTMODULE].[STARTDATE] as date) as 'Event Date',
SUM (case when [EVENTPLACE].[STATUS] IN ('Accepted','Attended') then 1 else 0 end) 'Total Bookings',
SUM (case when [EVENTPLACE].[STATUS] IN ('Accepted','Attended') AND [COURSEPLACE].[TYPE] = 'Application' then 1 else 0 end) 'Current Applicants'
..
)
Note : When you are using Single quotes to escape the space in alias name it will work but it will not work when using it as column names

Hope this helps
with cte as
(
SELECT [EVENTMODULE].[DESCRIPTION] as 'Event', cast([EVENTMODULE].[STARTDATE] as date) as 'Event Date',
SUM (case when [EVENTPLACE].[STATUS] IN ('Accepted','Attended') then 1 else 0 end) 'Total Bookings',
SUM (case when [EVENTPLACE].[STATUS] IN ('Accepted','Attended') AND [COURSEPLACE].[TYPE] = 'Application' then 1 else 0 end)
)
select Event,Event Date,Total Bookings,[Total Bookings]-[EVENTPLACE].[STATUS] AS 'Non-Applicants'
from cte

Try this:
SELECT * , [Non-Applicants] = [Total Bookings] - [Current Applicants]
FROM
(
SELECT [EVENTMODULE].[DESCRIPTION] as 'Event', cast([EVENTMODULE].[STARTDATE] as date) as 'Event Date',
SUM (case when [EVENTPLACE].[STATUS] IN ('Accepted','Attended') then 1 else 0 end) 'Total Bookings',
SUM (case when [EVENTPLACE].[STATUS] IN ('Accepted','Attended') AND [COURSEPLACE].[TYPE] = 'Application' then 1 else 0 end) 'Current Applicants' ...
) A

Related

Sum of a column in snowflake

I have two calculated columns with case statements. Now, I need to take Sum of those columns and need the difference in it.
For Ex.
Select Case when account = '30' and status='active' then value as value1,
case when account = '31' and status='active' then value as value2,
Sum(value1) - Sum(Value2) as Total_SUM
from table
How can we achieve this.. This gives me a missing group by clause error. I tried many things but did not work out.
Use conditional aggregation and sum the CASE expressions:
SELECT
SUM(CASE WHEN account = '30' THEN value ELSE 0 END) AS value1,
SUM(CASE WHEN account = '31' THEN value ELSE 0 END) AS value2,
SUM(CASE WHEN account = '30' THEN value ELSE 0 END) -
SUM(CASE WHEN account = '31' THEN value ELSE 0 END) AS Total_SUM
FROM yourTable
WHERE status = 'active';

SQL Count entries with value per Date

I have a table in SQL Server:
CREATE TABLE healthRegistration
(
ID uniqueidentifier PRIMARY KEY,
RegisterDateTime DateTime NOT NULL,
RUFeelingWell Bool NOT NULL
);
The RegisterDateTime is the date and time that the user created the register and RUFeelingWell is a boolean value.
I want to create a query that returns 3 columns: Register Date, Count of entries with RUFeelingWell = False on that date, Count of entries with RUFeelingWell = True on that date
How can I do this?
SELECT CAST(T.RegisterDateTime AS DATE)REGISTERDATE,
SUM
(
CASE
WHEN T.RUFeelingWell =1 THEN 1
ELSE 0
END
)AS TRUE_RECORDS,
SUM
( CASE
WHEN T.RUFeelingWell =0 THEN 1
ELSE 0
END
)AS FALSE_RECORDS
FROM healthRegistration AS T
GROUP BY CAST(T.RegisterDateTime AS DATE)
Try this query:
Select
Convert(char(8), RegisterDateTime, 112),
Sum(Case RUFeelingWell When 1 Then 1 Else 0 End) As wellnos,
Sum(Case RUFeelingWell When 0 Then 1 Else 0 End) As notwellnos
From healthRegistration
Group By Convert(char(8), RegisterDateTime, 112)
Order By Convert(char(8), RegisterDateTime, 112)
Here Convert(char(8), RegisterDateTime, 112) gives date in YYYYMMDD format so that entries for a day are summed together.
Boolean values are stored as 1 and 0 in the database

SQL Server : how to get DISTINCT COUNT for every GROUP

I have a table like this:
I would like to get the distinct counts for every GROUP:
How to get the result? Thank you.
You can use conditional aggregation:
select group,
sum(case when location = 'A' then 1 else 0 end) as a,
sum(case when location = 'B' then 1 else 0 end) as b,
sum(case when location = 'C' then 1 else 0 end) as c
from t
group by group;
Note that group is a very poor name for a column because it is a SQL reserved word.

SQL SUM BETWEEN TWO COUNT RESULT

SELECT
[Soldtopt],
[tradingname],
[DlvDate],
SUM(try_cast(Netvalue as float)) as Netvalue,
count(distinct SDDoc) as Salesdoc ,
count(distinct case when Netvalue = '0' then 1 else null end) as ZeroValue ,
sum (count(distinct SDDoc)) , (count(distinct case when Netvalue = '0' then 1 else null end)) As result
FROM [FOC].[dbo].[foc]
GROUP by Soldtopt,tradingname,DlvDate ORDER BY count (distinct SDDoc) DESC;
is this correct to way to bring the sum(
sum (count(distinct SDDoc)) , (count(distinct case when Netvalue = '0' then 1 else null end)) As result)
? or i am getting error "
Msg 130, Level 15, State 1, Line 13
Cannot perform an aggregate function on an expression containing an aggregate or a subquery."
[enter image description here][1]
[1]: https://i.stack.imgur.com/u1LGz.jpg hi in this result should be like 2,2,0,1 where as result shows like 35,35,35,35
Use SUM OVER()
SELECT [Soldtopt],
[tradingname],
[DlvDate],
Sum(try_cast(Netvalue as float)) AS Netvalue,
Count(DISTINCT SDDoc) AS Salesdoc,
Count(DISTINCT CASE WHEN Netvalue = '0' THEN 1 ELSE NULL END) AS ZeroValue, -- will always return 1
Sum (Count(DISTINCT SDDoc))OVER(),
Count(DISTINCT CASE WHEN Netvalue = '0' THEN 1 ELSE NULL END) AS result -- will always return 1
FROM [FOC].[dbo].[foc]
GROUP BY Soldtopt,
tradingname,
DlvDate
ORDER BY Count (DISTINCT SDDoc) DESC;
Also this Count aggregate will always return 1
Count(DISTINCT CASE WHEN Netvalue = '0' THEN 1 ELSE NULL END)
Adding sample data and expected result can fix the logical mistakes in your query
ORDER BY count (distinct SDDoc) DESC;
This will sort the data according to the number of col whose index is the value returned by the count function.
sum (count(distinct SDDoc))
This isn't a valid statement.
count(distinct case when Netvalue = '0' then 1 else null end)
Also try using a subquery in this count.
solved.count(distinct SDDoc) - count(distinct case when Netvalue = '0' then 1 else null end) As Result

How To Get Non-Null,Non-0 for Average with SqlServer Select

**Note: I need to go a little further and add NULLIF(0 or 5). I wrote a short post about my answer here:
http://peterkellner.net/2013/10/13/creating-a-compound-nullif-in-avg-function-with-sqlserver/
but am not happy with my solution)
I've got a table with results where attendees type in estimated attendance to a course. If they type 0 or leave it empty, I want ignore that and get the average of values typed in. I can't figure out how to add that constraint to my AVG function without having a where clause for the entire SQL. Is that possible? My code looks like this: (EstimatedNumberAttendees is what I'm going after).
SELECT dbo.SessionEvals.SessionId,
AVG(Cast (dbo.SessionEvals.CourseAsWhole as Float)) AS CourseAsWholeAvg,
COUNT(*),
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'On Time' then 1
else null
end) AS SpeakerOnTime,
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'Late' then 1
else null
end) AS SpeakerLate,
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'NoShow' then 1
else null
end) AS SpeakerNoShow,
COUNT(case
when dbo.SessionEvals.PercentFull = '10% to 90%' then 1
else null
end) AS PercentFull10to90,
COUNT(case
when dbo.SessionEvals.PercentFull = '> 90%' then 1
else null
end) AS PercentFullGreaterThan90,
COUNT(case
when dbo.SessionEvals.PercentFull = ' < 10% Full ' then 1
else null
end) AS PercentFullLessThan10,
AVG(Cast (dbo.SessionEvals.EstimatedNumberAttendees as Float)) AS
EstimatedAttending
FROM dbo.Sessions
INNER JOIN dbo.SessionEvals ON (dbo.Sessions.Id =
dbo.SessionEvals.SessionId)
WHERE dbo.Sessions.CodeCampYearId = 8
GROUP BY dbo.SessionEvals.SessionId
AVG omits NULLs. Therefore make it treat 0s as NULLs. Use NULLIF for that:
...
AVG(NULLIF(Cast (dbo.SessionEvals.CourseAsWhole as Float), 0)) AS CourseAsWholeAvg,
...
AVG(NULLIF(Cast (dbo.SessionEvals.EstimatedNumberAttendees as Float), 0)) AS EstimatedAttending
...
You can try to use an inner query to get the same sessions but exclude zero and null:
SELECT dbo.SessionEvals.SessionId,
(
SELECT AVG(SE1.CourseAsWhole)
FROM dbo.SessionEvals SE1
WHERE SE1.SessionId = dbo.SessionEvals.SessionId
AND ISNULL(SE1.CourseAsWhole, 0) <> 0
) AS CourseAsWholeAvg,
COUNT(*),
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'On Time' then 1
else null
end) AS SpeakerOnTime,
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'Late' then 1
else null
end) AS SpeakerLate,
COUNT(case
when dbo.SessionEvals.InstructorPromptness = 'NoShow' then 1
else null
end) AS SpeakerNoShow,
COUNT(case
when dbo.SessionEvals.PercentFull = '10% to 90%' then 1
else null
end) AS PercentFull10to90,
COUNT(case
when dbo.SessionEvals.PercentFull = '> 90%' then 1
else null
end) AS PercentFullGreaterThan90,
COUNT(case
when dbo.SessionEvals.PercentFull = ' < 10% Full ' then 1
else null
end) AS PercentFullLessThan10,
AVG(Cast (dbo.SessionEvals.EstimatedNumberAttendees as Float)) AS
EstimatedAttending
FROM dbo.Sessions
INNER JOIN dbo.SessionEvals ON (dbo.Sessions.Id =
dbo.SessionEvals.SessionId)
WHERE dbo.Sessions.CodeCampYearId = 8
GROUP BY dbo.SessionEvals.SessionId
SQL AVG function will by default ignore null values so you need to only exclude the 0s. Your AVG code can be changed to below:
AVG(nullif( Cast(dbo.SessionEvals.CourseAsWhole as Float), 0) AS CourseAsWholeAvg

Resources