Convert the students marks into respective grades
You need to concatenate the id and the letter grade inside the phrase:
'Student ? has grade: ?'
with this:
select
'Student ' || id || ' has grade: ' || CASE
WHEN max_grade < 20 then 'F'
WHEN max_grade < 40 then 'D'
WHEN max_grade < 60 then 'C'
WHEN max_grade < 80 then 'B'
ELSE 'A'
END AS Grade_details
FROM students
ORDER BY id;
SQL Query for Student mark functionality
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 correlating results, the basic step is the same; first, partition the problem in a bite-sized parts, and then integrate them as you solved each one of them, so it won'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
) and also the subquery itself (as x
). Anyway, this are just matter of style, I prefer 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
How to calculate student grade with SQL
Try this -
SELECT R.STUDENT, (Asst1+Asst2+Exam) AS TotalMark,
CASE WHEN (Asst1+Asst2+Exam) > 84.5
THEN 'A'
WHEN (Asst1+Asst2+Exam) < 84.5 AND (Asst1+Asst2+Exam) > 64.5
THEN 'B'
WHEN (Asst1+Asst2+Exam) < 64.5 AND (Asst1+Asst2+Exam) > 49.5
THEN 'C'
WHEN (Asst1+Asst2+Exam) < 49.5 AND (Asst1+Asst2+Exam) > 29.5
THEN 'D'
ELSE 'E'
END AS GRADE
FROM RESULTS R;
Find list of topper across each class when given individual scores for each subject
It would be clearer to use temporary tables to store results along the way and make the result traceable, but the solution can be achieved with a single query:
WITH student_marks AS (
SELECT Class_num, Name, SUM(Marks) AS student_total_marks
FROM School
GROUP BY Class_num, Name
)
SELECT Class_num, Name, student_total_marks
FROM (
SELECT Class_num, Name, student_total_marks, ROW_NUMBER() OVER(partition by Class_num order by student_total_marks desc, Class_num) AS beststudentfirst
FROM student_marks
) A
WHERE A.beststudentfirst = 1
The query within WITH statement calculate a sum of marks for every student in a class. At this point, subject is not required anymore. The result is temporarily stored into student_marks.
Next, we need to create a counter (beststudentfirst) using ROW_NUMBER to number the total marks from the highest to the lowest in each class (order by student_total_marks desc, Class_num). The counter should be reinitiated each time the class changes (partition by Class_num order).
From this last result, we only need the counter (beststudentfirst) with the value of one. It is the top student in each class.
Related Topics
Select Ids from Multiple Rows Where Column Values Satisfy One Condition But Not Another
How to Split One Column into Two Columns in SQL Server
1052: Column 'Id' in Field List Is Ambiguous
Duplicate Rows When Joining Tables
Sqlstate[01000]: Warning: 1265 Data Truncated for Column
Is There a Command to Test an SQL Query Without Executing It ( MySQL or Ansi SQL )
Postgresql Error: Fatal: Role "Username" Does Not Exist
How to Close Idle Connections in Postgresql Automatically
Removing Leading Zeroes from a Field in a SQL Statement
How to Select True/False Based on Column Value
Finding the Highest Average Salary in SQL
Insert Value into Table If Conidition Is Met At Least One Time
Grouping But With Keeping All Non-Null Values
I Want to Give Serial No in My Query According to Group
Sql Server Function to Return Minimum Date (January 1, 1753)
The Network Adapter Could Not Establish the Connection in SQL Developer