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';
Related
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.
I have a table that has a column called type which has either a value of invoiced or order and then another column holding the value along with a column holding the customer number etc.
I have written a script :-
select
customer,
(CASE WHEN TYPE = 'INVOICED' THEN SUM(INVTOTAL) else 0 END) AS INVTOTAL,
(CASE WHEN TYPE = 'ORDERS' THEN SUM(INVTOTAL) else 0 END) AS ORDERTOTAL
from
salestable
Why does it return the following?
customer INVTOTAL ORDERTOTAL
Joe Bloggs 1000 0
Joe Bloggs 0 1300
instead of
customer INVTOTAL ORDERTOTAL
Joe Bloggs 1000 1300
Sorry to ask such a novice question but I am new to SQL and learning it...
Thanks for any help!
Your query was missing a group by. Also use sum around case to avoid multiple rows.
select customer,
sum(CASE WHEN TYPE = 'INVOICED' THEN INVTOTAL else 0 END) AS INVTOTAL,
sum(CASE WHEN TYPE = 'ORDERS' THEN INVTOTAL else 0 END) AS ORDERTOTAL
from salestable
group by customer
You need to do a group by with the customer that will avoid the multiple rows.check the fiddle below.
create table tb1
(customer varchar(25),
type varchar(25),
invoice numeric(18,2)
);
insert into tb1(customer,type,invoice) values('Joe Bloggs','INVOICED',1000);
insert into tb1(customer,type,invoice) values('Joe Bloggs','ORDERS',1000);
select customer,
sum(CASE WHEN TYPE = 'INVOICED' THEN sum(invoice) else 0 END) AS INVTOTAL,
sum(CASE WHEN TYPE = 'ORDERS' THEN sum(invoice) else 0 END) AS ORDERTOTAL
from tb1
group by customer
fiddle with example
You need to put the entire case statment inside sum()
inorder to avoid grouping by type also else you will get this below error
Column 'tb1.type' is invalid in the select list because it is
not contained in either an aggregate function or the GROUP BY clause.
Because select returns a row for each row in the table matching the where filters. If no filters, then a result row for every row in table. If you want to "join" the rows, you could try grouping by the customer, like:
SELECT customer,
SUM(CASE WHEN TYPE = 'INVOICED' THEN INVTOTAL ELSE 0 END) as INVTOTAL,
SUM(CASE WHEN TYPE = 'ORDERS' THEN INVTOTAL ELSE 0 END) as ORDERTOTAL
FROM salestable
GROUP BY customer
**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
I have a SQL statement that has multiple case statements like the below:
SUM(CASE [Type]
WHEN 418
THEN CASE WHEN PMTS.DateCreated BETWEEN #sd AND #ed
AND( PMTS.Amount >0 OR PMTS.Mileage >0)
AND PMTS.PaymentEventID = 0 THEN Mileage END
ELSE 0 END) AS DriverMileage
But I need the result of the sum to set a variable and use that in the where in the WHERE clause.
Example below
DECLARE #contribution decimal
SElECT PMTS.VolunteerId ,
SET #contribution = SUM(CASE [Type]
WHEN 1003
THEN CASE WHEN PMTS.DateCreated BETWEEN #sd AND #ed
AND( PMTS.Amount >0 OR PMTS.Mileage >0)
AND PMTS.PaymentEventID = 0
THEN Amount END
ELSE 0 END) AS GPContributions
FROM PMTS WHERE #contribution >0
Many thanks
I don't think that you need a variable here, also please confirm the "case when" syntax used. Here is a sample query:
select * from
(SElECT PMTS.VolunteerId ,SUM(CASE [Type]
WHEN 1003
THEN CASE WHEN PMTS.DateCreated BETWEEN #sd AND #ed
AND( PMTS.Amount >0 OR PMTS.Mileage >0)
AND PMTS.PaymentEventID = 0
THEN Amount END
ELSE 0 END) AS GPContributions
FROM PMTS)as A WHERE GPContributions >0
I'm using SQL Server 2005. I'm looking to add up the columns (AM, Midday, Evening) to see which ones contains the value "YES" and then take that total and multiply it by the rate for each row for a client.
Here is the query I have so far:
Select
Sum(Case When morning = 'yes' Then 1 Else 0 End) am_total,
Sum(Case When midday = 'yes' Then 1 Else 0 End) midday_total
From services
where client_id = 24
with the following output
am_total midday_total
45 49
When I introduce the rate variable, my query starts telling me I need the group_by clause and I don't think I'm ready for that since I still need to add the am_total and the midday_total together first and then multiply that by the rate.
Ultimately, all I'm looking for is the grand total.
If I understand your question, maybe this is what you need
declare #rate int
set #rate = 2 /*what ever rate is */
select am_total * #rate as am, midday_total * #rate as midday
from (
Select
Sum(Case When morning = 'yes' Then 1 Else 0 End) am_total,
Sum(Case When midday = 'yes' Then 1 Else 0 End) midday_total
From services
where client_id = 24
)
You can also join another table and use its columns in calculation
Select
Sum(Case When morning = 'yes' Then 1 * u.rate Else 0 End) am_total,
Sum(Case When midday = 'yes' Then 1 * u.rate Else 0 End) midday_total
From services srv inner join users u on services.id = u.service_id -- assuming this is relation
pay attention on u.rate above