Find students who take most courses SQL - sql

Assume there's a table students containing student id, semester id and number of courses taken in each semester:
student semester num_courses
10001 23 3
10002 23 5
10003 23 1
10004 25 2
10005 25 3
10003 25 5
10000 26 4
10013 26 2
...
How can I find students in each semester who took the largest number of courses?
Expected output would be:
student semester num_courses
10002 23 5
10003 25 5
10000 26 4
...
I thought of using OVER PARTITION BY, but I'm not sure how to use it correctly with this type of query. What I got is not working as expected.
SELECT s.student, s.semester, MAX(s.num_courses) OVER (PARTITION BY s.semester) AS max
FROM students s;

Your idea is good. Now that you have the students' semester course counts along with the maximum semester course counts, compare the two:
SELECT semester, num_courses, student
FROM
(
SELECT
student,
semester,
num_courses,
MAX(num_courses) OVER (PARTITION BY semester) AS semester_max_num_courses
FROM students s
) with_max
WHERE num_courses = semester_max_num_courses
ORDER BY semester, student;
Another approach would be to select all maximum semester course counts and then use this to get the students:
SELECT semester, num_courses, student
FROM students
WHERE (semester, num_courses) IN
(
SELECT semester, MAX(num_courses)
from students
GROUP BY semester
)
ORDER BY semester, student;

With row_number() you can easily have a serial number in descending order of num_courses. Then just pick the rows with first serial number for each semister.
Subquery:
select student ,semester, num_courses from
(
Select student ,semester, num_courses, row_number()over(partition by semester
order by num_courses desc)rn from students
)t
where rn=1
Common table expression
With cte as
(
Select student ,semester, num_courses, row_number()over(partition by semester
order by num_courses desc)rn from students
)
select student ,semester, num_courses from cte where rn=1

Another approach, also if more than one student has max number of courses
WITH cte as
(
SELECT s.semester, MAX(s.num_courses) as num
FROM students s
GROUP BY s.semester
)
SELECT s.student, s.semester, s.num_courses FROM students s JOIN cte on s.semester =
cte.semester
WHERE cte.num = s.course
ORDER BY s.semester

If you want one row per semester, then in Postgres, I would recommend distinct on:
select distinct on (semester) s.*
from students s
order by semester, num_courses desc;
If you want all students who have the maximum number, then Thorsten's answer is appropriate.

Related

Selecting Third Highest Value SQLServer [duplicate]

This question already has answers here:
How to find third or nᵗʰ maximum salary from salary table?
(56 answers)
Closed 5 years ago.
I'm trying to return the name & grade of the student with the third highest assessment grade. I'm currently getting the right answer, but I feel like there's a better way to do it.
Dataset
CREATE TABLE Student(
Student_ID INT,
Student_Name VARCHAR(10)
)
INSERT INTO Student (Student_ID, Student_Name) VALUES (1,'Alex'),(2, 'Brett1'),(3,'Cora'),(4,'David'),(5,'Eleanor'),(6,'Brett2')
CREATE TABLE Grades(
Student_ID INT,
Assignment_ID INT,
Grade INT
)
INSERT INTO Grades (Student_ID, Assignment_ID, Grade) VALUES (1,10,90),(2,10,85),(3,10,75),(4,10,74),(1,11,80),(2,11,81),(4,11,88),(6,11,86),(2,12,84)
Attempted Solution
SELECT top 1 s.Student_Name, g.Grade
FROM Student s
INNER JOIN Grades g on s.Student_ID=g.Student_ID
WHERE g.Grade < 88
ORDER BY Grade DESC
Without the (WHERE g.Grade<88) it returns the top 3 results, this was a manual way to fix the issue
Thanks in advance~!
for obtain only the 3rd you could use the TOP 1 reverted of the top 3
select top 1 Student_name, Grade
from (
SELECT top 3 s.Student_Name, g.Grade
FROM Student s
INNER JOIN Grades g on s.Student_ID=g.Student_ID
ORDER BY Grade DESC ) t
order by Grade asc
"Newer" SQL Server versions (SQL Server 2012+):
SELECT s.Student_Name, g.Grade
FROM Student s
INNER JOIN Grades g on s.Student_ID=g.Student_ID
ORDER BY Grade DESC
OFFSET 2 FETCH FIRST 1 ROW ONLY
Use ROW_NUMBER window function
;with cte
AS (
SELECT s.Student_Name, g.Grade ,
RN = row_number()over(order by Grade desc)
FROM Student s
INNER JOIN Grades g on s.Student_ID=g.Student_ID
)
Select *
From cte
Where RN = 3

Name of Teacher with Highest Wage - recursive CTE

I am trying to get the max salary of each dept and display that teacher by first name as a separate column. So dept 1 may have 4 rows but one name showing for max salary. I'm Using SQL SERVER
With TeacherList AS(
Select Teachers.FirstName,Teachers.LastName,
Teachers.FacultyID,TeacherID, 1 AS LVL,PrincipalTeacherID AS ManagerID
FROM dbo.Teachers
WHERE PrincipalTeacherID IS NULL
UNION ALL
Select Teachers.FirstName,Teachers.LastName,
Teachers.FacultyID,Teachers.TeacherID, TeacherList.LVL +
1,Teachers.PrincipalTeacherID
FROM dbo.Teachers
INNER JOIN TeacherList ON Teachers.PrincipalTeacherID =
TeacherList.TeacherID
WHERE Teachers.PrincipalTeacherID IS NOT NULL)
SELECT * FROM TeacherList;
SAMPLE OUTPUT :
Teacher First Name | Teacher Last Name | Faculty| Highest Paid In Faculty
Eric Smith 1 Eric
Alex John 1 Eric
Jessica Sewel 1 Eric
Aaron Gaye 2 Aaron
Bob Turf 2 Aaron
I'm not sure from your description but this will return all teachers and the last row is the name of the teacher with the highest pay on the faculty.
select tr.FirstName,
tr.LastName,
tr.FacultyID,
th.FirstName
from Teachers tr
join (
select FacultyID, max(pay) highest_pay
from Teachers
group by FacultyID
) t on tr.FacultyID = t.FacultyID
join Teachers th on th.FacultyID = t.FacultyID and
th.pay = t.highest_pay
this will produce an unexpected result (duplicate rows) if there are more persons with the highest salary on the faculty. In such case you may use window functions as follows:
select tr.FirstName,
tr.LastName,
tr.FacultyID,
t.FirstName
from Teachers tr
join
(
select t.FirstName,
t.FacultyID
from
(
select t.*,
row_number() over (partition by FacultyID order by pay desc) rn
from Teachers t
) t
where t.rn = 1
) t on tr.FacultyID = t.FacultyID
This will display just one random teacher from faculty with highest salary.
dbfiddle demo
You can do this with a CROSS APPLY.
SELECT FirstName, LastName, FacultyID, HighestPaid
FROM Teachers t
CROSS APPLY (SELECT TOP 1 FirstName AS HighestPaid
FROM Teachers
WHERE FacultyID = t.FacultyID
ORDER BY Salary DESC) ca

SQL query asking for the ids of students that took only sections that had more than 10 students in them

I have 2 tables enroll(sid, grade, dname, cno, sectno) and
student(sid, sname, sex, age, year, gpa)
I have to write query asking for the ids of students that took only sections that had more than 10 students in them.
Why this query is not giving me correct result?
select student.sid
from student
where student.sid IN (select student.sid
from enroll
group by sectno, cno, dname
having count (distinct enroll.sid) > 10)
What about this query, is it correct?
select distinct sid
from enroll e1
where 10 < (select count (*)
from enroll e2
where e2.sectno = e1.sectno
and e2.cno = e1.cno
and e2.dname = e1.dname)
order by sid
Have a sub-query that returns sectno's for sections with less than 10
students. Do NOT IN that result.
select distinct sid
from enroll
where sectno not in (select sectno
from enroll
group by sectno
having count(sid) < 10)
Try using something like the below:
select sid
from enroll e1
where (select count (sectionId) from enroll e2) > 10
order by sid ASC
Note: Don't use distinct in this scenario.

How to aggregate top 5 numbers in SQL Server 2000

Hi i I am facing a problem, it is that the students can have more than 5 subjects but i have to sum of only 5 subjects total marks of which the student secured the highest. One way to say sum of top 5 total marks obtained by any student.
How do i proceed please help me. Thanks in advance.
In SQL 2000 you will need to use a subselect to determine how many rows with the same ID have a higher mark. Then Filter for rows that have less then 5 higher marked rows above it:
select
ID, Sum(Mark)
From Table1 t
where
(Select count(*)
from Table1 it
where it.id=t.id and it.mark>t.mark) <5
group by ID
ROW_NUMBER isn't in sql-server-2000 unfortunately. You can achieve the same result with a subquery though. Hopefully this is what you're looking for:
SELECT s.studentid, SUM(s.total_marks)
FROM students s
WHERE s.sub_code IN (SELECT TOP 5 sub_code
FROM students a
WHERE a.studentid = s.studentid
ORDER BY total_marks DESC)
GROUP BY studentid
Working in fiddle
Here is a query that gives you only the 5 hightest marks per student:
SELECT studentID, total_marks,
row_number() OVER (PARTITION BY studentID, ORDER BY total_marks DESC) as rowN
FROM studentTable
WHERE rowN <= 5
So to get the total:
SELECT studentID, SUM(total_marks)
FROM
(
SELECT studentID, total_marks,
row_number() OVER (PARTITION BY studentID, ORDER BY total_marks DESC) as rowN
FROM studentTable
WHERE rowN <= 5
) T
GROUP BY studentID

Sql Server: include column that is not part of an aggregate function or Group by clause

I have a StudentGrades table that has these columns:
StudentID | CourseID | Grade
I need to find the top student for each course(along with the course id and the grade thye got for the course. For example if there are a total of three courses taught at the school the query should return:
1111 3 93
2334 4 90
4343 6 100
Here's what I have so far. The following query
select CourseID, MAX(Grade) Grade
from StudentGrades group by CourseID;
Produces:
3 83
4 90
6 100
What is the best way to include the studentID column? I know that I can hold the above result in a temp table and join with the the original StudentGrades table where the CourseID and Score match the get the correct columns. Is there another way or better way to include StudentID?
Hope this makes sense.
Thanks!
SQL Server has a functionality for windowing functions.
WITH gradeList
AS
(
SELECT StudentID,
CourseID,
Grade,
DENSE_RANK() OVER (PARTITION BY CourseID
ORDER BY Grade DESC) RN
FROM tableName
)
SELECT StudentID,
CourseID,
Grade
FROM gradeList
WHERE rn = 1
SQLFiddle Demo
SQLFiddle Demo
SQLFiddle Demo (with duplicate student having the same score with the highest grade)