Question

I have a table with all players results:

  id  |result| user_id
------------------------
  1   | 130  | 5C382072
  2   | 145  | 5C382072
  3   | 130  | 8QHDTz7w
  4   | 166  | 6155B6D0
  5   | 100  | DFSA3444

Smaller result is better. I need to make query for leaderboard. Each player must appear once in leaderboard with his best result. If 2 players have equal results, the one with smaller id should appear first. So I'm expecting this output:

  id  |result| user_id
------------------------
  5   | 100  | DFSA3444
  1   | 130  | 5C382072
  3   | 130  | 8QHDTz7w
  4   | 166  | 6155B6D0

I can't get desired result, cause grouping by user_id goes before ordering it by result, id.

My code:

SELECT id, MIN(result), user_id
FROM results
GROUP BY user_id
ORDER BY result, id

It output something close to desired result, but id field is not connected to row with smallest user result, it can be any id from group with the same user_id. Because of that ordering by id not work at all.

EDIT:

What I didn't mention before is that I need to handle situations when user have identical results.

I came up with two solutions that I don't like. :)

1) A bit slow and ugly:

SELECT t1.*
FROM (SELECT * FROM results WHERE results_status=1) t1 
LEFT JOIN  (SELECT * FROM results WHERE results_status=1) t2 
  ON (t1.user_id = t2.user_id AND (t1.result > t2.result OR (t1.result = t2.result AND t1.id > t2.id)))
WHERE t2.id IS NULL
ORDER BY result, id

2) Ten times slower but more clear:

SELECT *
FROM results t1
WHERE id = (
  SELECT id 
  FROM results 
  WHERE user_id = t1.user_id AND results_status=1 
  ORDER BY result, id 
  LIMIT 1
)
ORDER BY result, id

I'm stuck. :(

Was it helpful?

Solution

This should get you close. Avoid MySQL's lenient (errant) GROUP BY syntax, which lets you form a GROUP BY clause without naming unaggregated columns from the SELECT list. Use standard SQL's GROUP BY syntax instead.

select t.user_id, m.min_result, min(t.id) id
from results t
inner join (select user_id, min(result) min_result
            from results
            group by user_id) m
        on t.user_id = m.user_id
       and t.result = m.min_result
group by t.user_id, m.min_result

OTHER TIPS

Edit: I think you need a subquery:

SELECT a.id, a.result, a.user_id FROM results a 
WHERE a.user_id, a.result IN (SELECT b.user_id, MIN(b.result) FROM results b 
    GROUP BY b.user_id)
ORDER BY a.user_id

This will return an undefined id if the same user had the same score more than once, but will order the users correctly and will match id to the correct user_id.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top