Sunteți pe pagina 1din 4

You just have to partition the problem into some bite-sized steps and solve each

one by one
First, get the maximum score in each subject:
select SubjectID, max(MarkRate)
from Mark
group by SubjectID;
Then query who are those that has SubjectID with max MarkRate:
select SubjectID, MarkRate, StudentID
from Mark
where (SubjectID,MarkRate)
in
(
select SubjectID, max(MarkRate)
from Mark
group by SubjectID
)
order by SubjectID, StudentID;
Then obtain the Student's name, instead of displaying just the StudentID:
select SubjectName, MarkRate, StudentName
from Mark
join Student using(StudentID)
join Subject using(SubjectID)
where (SubjectID,MarkRate)
in
(
select SubjectID, max(MarkRate)
from Mark
group by SubjectID
)
order by SubjectName, StudentName
Database vendors' artificial differences aside with regards to joining and corre
lating results, the basic step is the same; first, partition the problem in a bi
te-sized parts, and then integrate them as you solved each one of them, so it wo
n't be as confusing.
Sample data:
CREATE TABLE Student
(StudentID int, StudentName varchar(6), Details varchar(1));
INSERT INTO Student
(StudentID, StudentName, Details)
VALUES
(1, 'John', 'X'),
(2, 'Paul', 'X'),
(3, 'George', 'X'),
(4, 'Paul', 'X');
CREATE TABLE Subject
(SubjectID varchar(1), SubjectName varchar(7));
INSERT INTO Subject
(SubjectID, SubjectName)

VALUES
('M', 'Math'),
('E', 'English'),
('H', 'History');
CREATE TABLE Mark
(StudentID int, SubjectID varchar(1), MarkRate int);
INSERT INTO Mark
(StudentID, SubjectID, MarkRate)
VALUES
(1, 'M', 90),
(1, 'E', 100),
(2, 'M', 95),
(2, 'E', 70),
(3, 'E', 95),
(3, 'H', 98),
(4, 'H', 90),
(4, 'E', 100);
Live test here: http://www.sqlfiddle.com/#!1/08728/3
IN tuple test is still a join by any other name:
Convert this..
select SubjectName, MarkRate, StudentName
from Mark
join Student using(StudentID)
join Subject using(SubjectID)
where (SubjectID,MarkRate)
in
(
select SubjectID, max(MarkRate)
from Mark
group by SubjectID
)
order by SubjectName, StudentName
..to JOIN:
select SubjectName, MarkRate, StudentName
from Mark
join Student using(StudentID)
join Subject using(SubjectID)
join
(
select SubjectID, max(MarkRate) as MarkRate
from Mark
group by SubjectID
) as x using(SubjectID,MarkRate)
order by SubjectName, StudentName
Contrast this code with the code immediate it. See how JOIN on independent query
look like an IN construct? They almost look the same, and IN was just replaced
with JOIN keyword; and the replaced IN keyword with JOIN is in fact longer, you
need to alias the independent query's column result(max(MarkRate) AS MarkRate) a

nd also the subquery itself (as x). Anyway, this are just matter of style, I pre
fer IN clause, as the intent is clearer. Using JOINs merely to reflect the data
relationship.
Anyway, here's the query that works on all databases that doesn't support tuple
test(IN):
select sb.SubjectName, m.MarkRate, st.StudentName
from Mark as m
join Student as st on st.StudentID = m.StudentID
join Subject as sb on sb.SubjectID = m.SubjectID
join
(
select SubjectID, max(MarkRate) as MaxMarkRate
from Mark
group by SubjectID
) as x on m.SubjectID = x.SubjectID AND m.MarkRate = x.MaxMarkRate
order by sb.SubjectName, st.StudentName
Live test: http://www.sqlfiddle.com/#!1/08728/4
shareimprove this answer
edited May 13 '12 at 11:58
answered May 13 '12 at 7:52
Michael Buen
26.6k35994
add a comment
up vote
2
down vote
My attempt - I'd start with the max mark and build from there
Schema:
CREATE TABLE Student (
StudentId int,
Name nvarchar(30),
Details nvarchar(30)
)
CREATE TABLE Subject (
SubjectId int,
Name nvarchar(30)
)
CREATE TABLE Marks (
StudentId int,
SubjectId int,
Mark int
)
Data:
INSERT INTO Student (StudentId, Name, Details)
VALUES (1,'Alfred','AA'), (2,'Betty','BB'), (3,'Chris','CC')

INSERT INTO Subject (SubjectId, Name)


VALUES (1,'Maths'), (2, 'Science'), (3, 'English')
INSERT INTO Marks (StudentId, SubjectId, Mark)
VALUES
(1,1,61),(1,2,75),(1,3,87),
(2,1,82),(2,2,64),(2,3,77),
(3,1,82),(3,2,83),(3,3,67)
GO
My query would have been:
;WITH MaxMarks AS (
SELECT SubjectId, MAX(Mark) as MaxMark
FROM Marks
GROUP BY SubjectId
)
SELECT s.Name as [StudentName], sub.Name AS [SubjectName],m.Mark
FROM MaxMarks mm
INNER JOIN Marks m
ON m.SubjectId = mm.SubjectId
AND m.Mark = mm.MaxMark
INNER JOIN Student s
ON s.StudentId = m.StudentId
INNER JOIN Subject sub
ON sub.SubjectId = mm.SubjectId
SQL Fiddle Example
Find the max mark for each subject
Join Marks, Student and Subject to find the relevant details of that highest
mark
This also take care of duplicate students with the highest mark
Results:
STUDENTNAME SUBJECTNAME
MARK
Alfred English
87
Betty Maths
82
Chris Maths
82
Chris Science
83

S-ar putea să vă placă și