Reputation: 1619
I have a StudentDetails table as below
select * from StudentDetails
And we have Class table as below
select * from Class
I know by using group by and aggregate function we can display easily maximum marks obtained in each class by below query
select C.Name as 'ClassName',
MAX(SD.Mark) as 'Max Mark'
from StudentDetails SD
inner join Class C on SD.classid = C.ClassId group by C.Name
giving below result
But now I need to display the student name also along with the maximum mark in each class by using group by and aggregate function. I used below query but it did not give expected result.
select C.Name as 'ClassName',
SD.Name as 'Student Name',
Max(SD.Mark) as 'Max Mark'
from StudentDetails SD
inner join Class C on SD.classid = C.ClassId
group by C.Name,SD.Name
giving below result .
This result is not as expected, I need a query which will result
Division A , Mrx , 536
Division B , MrC , 535.
using group by and aggregate function Please somebody help me..
Upvotes: 0
Views: 1694
Reputation: 2017
You can use a derived table. The derived table takes the ClassID with it's MAX(Mark). The receiving query and joins apply the appropriate descriptions.
SELECT C.Name
,SD.Name
,dT.MaxMark
FROM (
--Gets the MaxMark per ClassID
SELECT S.ClassID
,MAX(Mark) [MaxMark]
FROM StudentDetails S
GROUP BY S.ClassID
) AS dT INNER JOIN StudentDetails SD ON SD.Mark = dT.MaxMark
INNER JOIN Class C ON C.ClassID = dT.ClassID
Gives output:
Name Name MaxMark
Division A MrX 536
Division B MrC 535
If you want to examine the full code: sqlfiddle
Upvotes: 2
Reputation: 94914
You want to compare a student class result with the maximum class result. The easiest way to do this is with MAX OVER
:
select classname, studentname, mark
from
(
select
c.name as classname,
sd.name as studentname,
sd.mark,
max(sd.mark) over (partition by sd.class) as class_max_mark
from studentdetails s
join class c on c.classid = sd.classid
) analysed
where mark = class_max_mark;
If you are forced to use GROUP BY
, then you'd want:
select
c.name as classname,
sd.name as studentname,
sd.mark
from studentdetails s
join class c on c.classid = sd.classid
where (sd.classid, sd.mark) in
(
select classid, max(mark)
from studentdetails
group by classid
);
SQL Server, however, doesn't support IN
clauses with multiple columns. So you need a join which obfuscates the query slightly:
select
c.name as classname,
sd.name as studentname,
sd.mark
from studentdetails s
join class c on c.classid = sd.classid
join
(
select classid, max(mark) as max_mark
from studentdetails
group by classid
) m on m.classid = sd.classid and m.max_mark = sd.mark;
Upvotes: 0
Reputation: 37367
Try this:
select B.Name, A.Name, A.Mark from (
select Name, Mark, ClassId, MAX() over (partition by ClassId) as MaxMark from StudentDetails
) as A join Class as C on A.ClassId = C.ClassId
where A.Mark = A.MaxMark
Upvotes: 0
Reputation: 10701
You may use a correlated subquery in WHERE
select C.Name as 'ClassName',
SD.name,
SD.Mark as 'Max Mark'
from StudentDetails SD
inner join Class C on SD.classid = C.ClassId
where sd.mark = (select max(mark) from StudentDetails s where sd.classid = s.classid)
Upvotes: 0
Reputation: 816
Make use of dense_rank
select StudName, ClsName, Mark from
(
select Dense_Rank() over(partition by #Table_studentDetails.classId
order by Mark desc) Rank,
#Table_studentDetails.Name StudName, #Table_Class.Name ClsName,Mark
from #Table_studentDetails inner join #Table_Class on
#Table_studentDetails.classid = #Table_Class.classid
)T
where Rank = 1
Upvotes: 0
Reputation: 12309
Try this :
WITH CTE AS(
select C.Name as 'ClassName',
MAX(SD.Mark) as 'Max Mark'
from StudentDetails SD
inner join Class C on SD.classid = C.ClassId group by C.Name
)
SELECT STudentName,*
FROM CTE
INNER JOIN StudentDetails SD ON Marks = [Max Marks]
Upvotes: 1