LalitBoliya


Hi,

I have 2 tables:

Class - ClassID(int), ClassName(varchar)

Student - StudentID(int), ClassID, Age(smallint), Sex(nchar(1)), DateOfJoining(datetime)

I want to write a query that gives me the Top 10 Class which have maximum no. of student joining during the past 6 months. The query should include the following :

ClassName, Count(StudentID), Avg(Age), Avg(Sex)

From the avg(sex) i mean which was the sex which got enrolled more - ie. M or F. All I want is to find out that if in Class A, no of students enrolled were 50 and out of that 30 were Boys, then the end result of the query should be

Name Count Age Sex

ClassA 50 14 M(60%)

.....

ClassR 40 13 F(80%) ---- assuming out of 40, 32 are girls.

and so on....

How do I do this

Thanks.




Re: Aggregating records and displaying

hunchback


Try:

select

[name],

cnt,

case

when sum_m > sum_f then 'M('

when sum_m < sum_f then 'F('

else 'MF('

end + str(

(

case

when sum_m >= sum_f then sum_m

when sum_m < sum_f then sum_f

end * 100.00) / nullif(cnt, 0), 5, 2) + ')'

from

(

select

c.name,

count(*) as cnt,

avg(s.age) as avg_age,

sum(case when s.sex = 'M' then 1 else 0 end) as sum_m,

sum(case when s.sex = 'F' then 1 else 0 end) as sum_f

from

dbo.class as c

inner join

dbo.student as s

on c.classid = s.classid

where

s.DateOfJoining >= convert(varchar(6), dateadd(month, -5, getdate()), 112) + '01'

) as t

AMB






Re: Aggregating records and displaying

Arnie Rowland

Alejandro,

Isn't there likely to be a problem here with concatenation (numbers with strings...)

case

when sum_m > sum_f then 'M('

when sum_m < sum_f then 'F('

else 'MF('

end + str(

(

case

when sum_m >= sum_f then sum_m

when sum_m < sum_f then sum_f

end * 100.00) / nullif(cnt, 0), 5, 2) + ')'







Re: Aggregating records and displaying

hunchback

Hi Arnie,

Could be, I did not test the statement. I am using function STR to convert the result number to string.

case

when sum_m > sum_f then 'M('

when sum_m < sum_f then 'F('

else 'MF('

end + str(

(

case

when sum_m >= sum_f then sum_m

when sum_m < sum_f then sum_f

end * 100.00) / nullif(cnt, 0), 5, 2) + ')'

AMB





Re: Aggregating records and displaying

LalitBoliya

Hi,

Thanks hunchback for the quick reply.

I keep getting the error :

Column 'dbo.class.Name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

I tried adding the GroupBy to the inner select without much success.

Any clues!!

Thanks.





Re: Aggregating records and displaying

hunchback

My fault, I forgot the "group by" and the "order by" clauses.

select

[name],

cnt,

case

when sum_m > sum_f then 'M('

when sum_m < sum_f then 'F('

else 'MF('

end + str(

(

case

when sum_m >= sum_f then sum_m

when sum_m < sum_f then sum_f

end * 100.00) / nullif(cnt, 0), 5, 2) + '%)'

from

(

select top 10

c.name,

count(*) as cnt,

avg(s.age) as avg_age,

sum(case when s.sex = 'M' then 1 else 0 end) as sum_m,

sum(case when s.sex = 'F' then 1 else 0 end) as sum_f

from

dbo.class as c

inner join

dbo.student as s

on c.classid = s.classid

where

s.DateOfJoining >= convert(varchar(6), dateadd(month, -5, getdate()), 112) + '01'

group by

c.name

order by

cnt DESC

) as t

AMB





Re: Aggregating records and displaying

LalitBoliya

Smile

I tried that..however put the groupby in the outer select. I need some sleep. hehe..anyways thanks.





Re: Aggregating records and displaying

Kent Waldrop Jn07

It is definitely not better, but I did seem to get the correct type of answer with this:

Code Snippet

select q.[name] as Name,
classCount,
avgAge as Age,
case when mCount > fCount
then 'M(' + convert(varchar(3),
cast( 100.0 * mCount / classCount as int))
+ '%)'
when fCount > mCount
then 'F(' + convert(varchar(3),
cast( 100.0 * fCount / classCount as int))
+ '%)'
else 'MF(50/50)'
end as Sex
from ( select a.classId,
a.classCount,
avg (age) as avgAge,
sum(case when Sex = 'M' then 1 else 0 end)
as mCount,
sum(case when Sex = 'F' then 1 else 0 end)
as fCount
from ( select top 10 classId,
count(*) as classCount
from student
where dateOfJoining >= dateadd(mm, -6, getdate())
group by classId
order by count(*) desc, classId
) a
join student b
on a.classId = b.classId
group by a.ClassId,
a.classCount
) p
join Class q
on p.classId = q.classId

/*
Name classCount Age Sex
-------------------- ----------- ----------- ---------
Class #80 381 22 F(50%)
Class #61 353 22 F(51%)
Class #43 351 21 F(50%)
Class #54 350 21 M(50%)
Class #20 358 21 F(51%)
Class #87 350 22 F(51%)
Class #24 360 21 M(50%)
Class #22 367 22 M(52%)
Class #40 354 22 MF(50/50)
Class #70 353 22 M(52%)
*/





Re: Aggregating records and displaying

LalitBoliya

Thanks. Both the queries are fine. I will use the profiler and select the best one.

Thanks again to all.