I have the following tables for a university database:
takes(ID, course_id, sec_id, semester, year, grade)
section(course_id, sec_id, semester, year)
I need to determine which sections had the maximum number of students enrolled in Fall semester of 2009.
I have tried variations of the following query:
with sec_enrollment as(
select course_id, sec_id, count(ID) as enrollment
from section natural join takes
where semester = 'Fall' and year = 2009
group by course_id, sec_id)
select course_id, sec_id, enrollment
from sec_enrollment
group by course_id, sec_id, enrollment
having enrollment = max(enrollment)
The above query returns all sections from Fall 2009 instead of just the sections with max enrollment. It seems that my 'having' clause is being ignored.
If I use the query:
with sec_enrollment as(
select course_id, sec_id, count(ID) as enrollment
from section natural join takes
where semester = 'Fall' and year = 2009
group by course_id, sec_id)
select max(enrollment)
from sec_enrollment
I can get the desired value for the maximum enrollment. I just can't figure out how to get the desired value along with course_id and sec_id of sections that contain that maximum. I'm thinking that the 'group by' clause is screwing things up, but I can't configure it any other way without drawing an error (ORA-00979: not a GROUP BY expression). Any help would be greatly appreciated
This is one way to do it using one more cte.
with sec_enrollment as (
select course_id, sec_id, count(ID) as enrollment
from section natural join takes
where semester = 'Fall' and year = 2009
group by course_id, sec_id)
, max_enrollment as (
select max(enrollment) as maxenrollment from sec_enrollment)
select course_id, sec_id
from sec_enrollment s
join max_enrollment m on s.enrollment = m.maxenrollment
Order the results in descending order by the enrollment count and then limit the results to 1 record.
with sec_enrollment as(
select course_id, sec_id, count(ID) as enrollment
from section natural join takes
where semester = 'Fall' and year = 2009
group by course_id, sec_id)
select course_id, sec_id, enrollment
from sec_enrollment
where ROWNUM = 1
order by enrollment DESC
You could write the query simpler as:
select course_id, sec_id, enrollment
from (
select s.course_id, s.sec_id, count(t.ID) as enrollment
from section s join takes t
where s.semester = 'Fall' and s.year = 2009
group by s.course_id, s.sec_id
order by count(t.ID)
)
where rownuw <= 1
When you have to find the item who has the max value, you don't need to find the max value and later find the item who has that value. There are two operations when you could just find the max and the item in the same operation, with a sort operation.
Related
I have a Table like that
and i want to see average score(if student have 3 scores for each course, student can join many course) for each student for each course.
But I couldn't create the sql query.
Are you just looking for aggregation?
select student_id, course_id, avg(score * 1.0) as avg_score
from exam_result
group by student_id, course_id
having count(*) >= 3;
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.
book name : Database System Concept / author : Silberschatz, Korth, Sudarshan
problem : Find the total number of (distinct) students who have taken course sections taught by the instructor with ID 10101
answer :
select count(distinct ID)
from takes
where (course_id, sec_id, semester, year) in
(select course_id, sec_id, semester, year
from teaches
where teaches.ID = 10101
);
my query :
select count (distinct ID)
from takes
where course_id in (SELECT course_id from teaches where teaches.ID = 10101);
Do I have to be a correct answer?
I need a little help with the following query. I need to find:
Average number of people per semester of each campus
My table structure is:
table name - registration
columns
student_id
campus
year
batch
semester
and with the help of campus, year, semester and batch I can identify each unique semester. More over my student_id repeats itself in the db.
I did following but it won't help. So I need some help.
SELECT semester,year,campus
FROM regestration
GROUP BY semester, year, campus
ORDER BY count(*) desc
Try something like:
SELECT year,campus, AVG(CountOfStudents)
FROM
(
SELECT semester,year,campus, count(*) as CountOfStudents
FROM regestration
GROUP BY semester, year, campus
) t
GROUP BY year, campus
To get the number of students in each campus each semester you need to add COUNT(*) to your query:
SELECT semester, year, campus, COUNT(*) as students
FROM registration
GROUP BY semester, year, campus
I don't know what average you want here, though.
How about
select avg(students), campus from (
select count(student_id) students, campus from registration
group by semester, year, campus
) group by campus
SELECT campus,semester, AVG(CountOfStudents)
FROM
(
SELECT semester,year,campus, count(*) as CountOfStudents
FROM regestration
GROUP BY semester, year, campus,student_id
) t
GROUP BY campus,semester
I need to do is to find the average number of people per semester of each campus
My table structure is:
Table name - registration
student_id
campus
year
batch
semester
campus, year, semester and batch these can help identify unique records, where as student_id may repeat itself the query above gives wrong answer.
Follow these steps:
remove student_ID from the GROUP BY clause and
add DISTINCT inside COUNT()
query,
SELECT campus, semester, AVG(CountOfStudents)
FROM
(
SELECT semester, year, campus, count(DISTINCT student_id) as CountOfStudents
FROM registration
GROUP BY semester, year, campus
) t
GROUP BY campus, semester