Reputation: 23
I have a list of a group of students, their subjects, grades and the amount of tries for each subject. The subjects repeat since some students try multiple times to pass. I need to select the student with most failed subjects but I cant count the repeated fails of a same subject, I need to keep in mind only the last attempt.
+-----------+---------------+-----------+-------------+
| [ name ] | [ subject ] | [ grade ] | [ attempt ] |
+-----------+---------------+-----------+-------------+
| [ Peter ] | [ math ] | [ 6 ] | [ 1 ] |
| [ Peter ] | [ math ] | [ 7 ] | [ 2 ] |
| [Jessica] | [ chemistry ] | [ 8 ] | [ 1 ] |
| [Jesicca] | [ spanish ] | [ 9 ] | [ 1 ] |
+-----------+---------------+-----------+-------------+
I tried selecting the failed subjects and group them by alumns but when I also try to include the last attempt, the result is only one subject with the last attempt instead of all the subjects per alumn.
Select
a.name, count(am.subject), am.attempt
from
alumnos a, alumnos_materias am
where
a.i_alumn = am.i_alumn and
(am.attempt = (select max(attempt)
from alumn_subject))
group by
a.name, am.attempt
having
am.i_subject = (select i_subject
from alumn_subject
where grade < 7)
I need the student with the most failed subjects, not the most attempts failed.
Upvotes: 1
Views: 104
Reputation: 29667
How about using a HAVING clause to get those with failed subjects.
Then get the top 1 with most fails from that.
SELECT
a.name,
COUNT(fails.subject) AS total_failed_subjects
FROM
(
SELECT i_alumn, subject
FROM alumnos_materias
GROUP BY i_alumn, subject
HAVING MAX(grade) <= 6
) fails
JOIN alumnos a ON a.i_alumn = fails.i_alumn
GROUP BY a.i_alumn, a.name
ORDER BY COUNT(fails.subject) DESC
FETCH FIRST 1 ROWS ONLY;
A test on db<>fiddle here
But if you really need the last attempt?
Then you could use ROW_NUMBER to filter on that before counting the fails.
SELECT
a.name,
COUNT(fails.subject) AS total_failed_subjects
FROM
(
SELECT i_alumn, subject, grade, attempt,
ROW_NUMBER() OVER (PARTITION BY i_alumn, subject ORDER BY attempt DESC) AS rn
FROM alumnos_materias
) fails
JOIN alumnos a ON a.i_alumn = fails.i_alumn
WHERE rn = 1 AND grade <= 6
GROUP BY a.i_alumn, a.name
ORDER BY COUNT(fails.subject) DESC
FETCH FIRST 1 ROWS ONLY;
Upvotes: 2
Reputation: 1270021
How about using conditional aggregation? To get the students order by the number of fails
select a.name,
count(distinct case when grade < 7 then subject end) as num_failed_subjects
from alumnos a join
alumnos_materias am
on a.i_alumn = am.i_alumn
group by a.name
order by num_failed_subjects desc;
Your question is a little vague on what you need:
fetch first 1 row only
.where rownum = 1
.rank()
or dense_rank()
.Upvotes: 0