SQL query with GROUP BY to show badges and points by user and course
Directly based on the current tables definition, I agree that it doesn't seem possible to have a better way of querying the needed results.

But it appears that performance might be improved using a slightly different approach, assuming that likely:


the number of courses and badges is reduced, compared to the number of users
courses and badges have relatively stable content (don't change daily!)


In the other hand we can notice that, in the current approach, courseAVG is computed again when the query is launched (more over, I'm not sure the optimizer takes care of computing it only once, rather than for each user/course pair!).

So an alternative approach might be:


add a pointsavg field to the Courses table
compute it in a separate UPDATE query (could be launched through a trigger applying AFTER INSERT and AFTER UPDATE on Badges and Courses


Here is it:

UPDATE Courses c
SET pointsavg = (
  SELECT AVG(points)
  FROM Badges b
  WHERE b.courseid = c.courseid
  GROUP BY courseid
);


Then we can simply use this pointsavg in the main query:

SELECT
  u.username,
  SUM(b.points) AS userCoursePoints,
  c.coursename,
  c.pointsavg AS courseAVG
FROM
  Users u,
  BadgeAssignments ba,
  Badges b,
  Courses c
WHERE ba.userid = u.id
  AND b.id = ba.badgeid
  AND c.courseid = b.courseid
GROUP BY u.username, b.courseid


Note that I took the opportunity to output username and coursename instead of their simple id, supposing it's closer to what is generally needed.

Here is the SQL fiddle: