views:

677

answers:

6

I have a table with game scores, allowing multiple rows per account id: scores (id, score, accountid). I want a list of the top 10 scorer ids and their scores.

Can you provide an sql statement to select the top 10 scores, but only one score per account id?

Thanks!

+2  A: 

select top 10 username, max(score) from usertable group by username order by max(score) desc

Danimal
Is 'top 10' new? I don't remember seeing it before?
zigdon
depends on the DBMS -- it was new to SQL Server in 2000
Danimal
I should have specified mysql. Limit did the trick. Thanks.
Kenzie
A: 

PostgreSQL has the DISTINCT ON clause, that works this way:

SELECT DISTINCT ON (accountid) id, score, accountid
FROM scoretable
ORDER BY score DESC
LIMIT 10;

I don't think it's standard SQL though, so expect other databases to do it differently.

Neall
+4  A: 
select username, max(score) from usertable group by username order by max(score) desc limit 10;
zigdon
this one needs a "desc" on the order by
Magnar
Updated, thanks.
zigdon
+2  A: 

First limit the selection to the highest score for each account id. Then take the top ten scores.

SELECT TOP 10 AccountId, Score
FROM Scores s1
WHERE AccountId NOT IN 
    (SELECT AccountId s2 FROM Scores 
     WHERE s1.AccountId = s2.AccountId and s1.Score > s2.Score)
ORDER BY Score DESC
Eclipse
Turns out this seems better because it selects the entire row. The other max query only tacked on the max score to a random row for each accountid.
Kenzie
Fixed: SELECT * FROM scores s1 WHERE accountid NOT IN (SELECT accountid FROM scores s2 WHERE s1.accountid = s2.accountid and s1.score < s2.score) ORDER BY score DESC
Kenzie
Only remaining issue I have with this query is that I'm getting more than one row per accountid when that account has more than one occurrence of it's top score. So if accoundid 6 has scores of 50, 75, 40, 75 then the query returns both rows with the score of 75.
Kenzie
+1  A: 
SELECT accountid, MAX(score) as top_score
FROM Scores
GROUP BY accountid,
ORDER BY top_score DESC
LIMIT 0, 10

That should work fine in mysql. It's possible you may need to use 'ORDER BY MAX(score) DESC' instead of that order by - I don't have my SQL reference on hand.

John Fiala
A: 

I believe that PostgreSQL (at least 8.3) will require that the DISTINCT ON expressions must match initial ORDER BY expressions. I.E. you can't use DISTINCT ON (accountid) when you have ORDER BY score DESC. To fix this, add it into the ORDER BY:

SELECT DISTINCT ON (accountid) *
FROM scoretable
ORDER BY accountid, score DESC
LIMIT 10;

Using this method allows you to select all the columns in a table. It will only return 1 row per accountid even if there are duplicate 'max' values for score.

This was useful for me, as I was not finding the maximum score (which is easy to do with the max() function) but for the most recent time a score was entered for an accountid.