Reputation: 1289
I have an SQL statement that grabs the grades of different activity types (Homework, Quiz, etc), and if there's a drop lowest for that type, it drops, else, it remains. The errors are below as well as the SQL Code.
SELECT Student.firstName, Student.lastName, 'Grades' =
CASE
WHEN Grades.activityType = 'Homework' THEN
CASE WHEN Policy.drop_hw = 1 THEN
(AVG(SUM(Grades.grade) - MIN(Grades.grade))) * (Policy.homework / 100)
ELSE
(AVG(Grades.grade) * (Policy.homework / 100))
END
END, Course.courseNum, Course.sectNum, Grades.activityType
FROM ...
Here are the errors I'm getting:
- Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
- Column 'Policy.drop_hw' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Upvotes: 4
Views: 2730
Reputation: 9413
Look into analytical functions. (SO question, Oracle documentation).
Something like this:
AVG(Grades.grade) OVER (PARTITION BY Grades.student_id) AS avg_of_grades
and:
(AVG(SUM(Grades.grade) - MIN(Grades.grade))) OVER (PARTITION BY Grades.student_id) AS avg_grades_with_drop
Set the partitioning with whatever makes sense in your case; we can't tell since you omitted the FROM ...
in your example.
You can then use those column aliases in any calculations inside your CASE
statement.
Upvotes: 3
Reputation: 2469
The sum-operator gives one result (per group). The min-operator, too. So over what should the avg-operator aggregate?
Upvotes: 0
Reputation: 425341
If you only need to drop one lowest grade (in case of ties)
SELECT student_id, AVG(grade)
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY grade) rn
FROM my_tables
)
WHERE NOT (drop_hw = 1 AND rn = 1)
GROUP BY
student_id
If you need to drop all lowest grades:
SELECT student_id, AVG(grade)
FROM (
SELECT *, MIN(grade) OVER (PARTITION BY student_id) mingrade
FROM my_tables
)
WHERE NOT (drop_hw = 1 AND grade = mingrade)
GROUP BY
student_id
Upvotes: 1