Search code examples
mysqlgroupwise-maximum

PDO Return highest integer value and no duplicate entries


I am not sure if this question has been asked yet but I don't know how to word it better :)

I have a table with game results. I need to return the top 10 results (for a leaderboard) but my results has to return the highest game per player and not replicate the player (so I am looking for each players highest score and based on that the top 10 players, not say if I am 1st and 3rd on scores to show me twice).

The SQL I am using at the moment is:

 SELECT 
        `games`.`score`,
        CONCAT(`users`.`full_name`) AS `name`,
        `users`.`facebook_id`
        FROM 
        `games`,
        `users` 
        WHERE 
        `games`.`user_id`=`users`.`id` 
        AND `users`.`id` IN ('user ids goes here') 
        AND `games`.`status`=2
        ORDER BY 
        `games`.`score` DESC 
        LIMIT 10";

Can this be done with a single query or would it be best to work on the returned array and create my desired results from there?

UPDATE:

To best illustrate, say we have the following results:

Jack - 300 points
Jill - 280 points
Gareth - 250 points
Jack - 240 points (this is the same jack)
Peter - 230 points 
....

I want to return from all of the games the top 10 players based on their highest score, so not neccesarily 10 results, but I'm looking for a result which would then return the following:

Jack - 300 points
Jill - 280 points
Gareth - 250 points
Peter - 230 points 

So The 2nd Jack is removed because he is already on the list just with a higher score.

I hope this helps :)


Solution

  • Okay, let's do this step by step.

    With this query, we get a list of games and their players, sorted by game and score. We add a rownumber which resets to 1 for each game.

    SELECT 
    games.game_id,
    `games`.`score`,
    CONCAT(`users`.`full_name`) AS `name`,
    `users`.`facebook_id`,
    @row_num := if(@game != games.game_id, 1, @row_num + 1) AS rownumber,
    @game := games.game_id
    FROM 
    `games`
    INNER JOIN users ON `games`.`user_id`=`users`.`id` 
    , (select @row_num := 1, @game := NULL) variables
    WHERE 
    `users`.`id` IN ('user ids goes here') 
    AND `games`.`status`=2
    ORDER BY 
    games.game_id, /*or something*/
    `games`.`score` DESC 
    

    Now we can get the top 10 players for each game by putting above query into this

    SELECT * FROM (
    <above query here>
    ) subquery_alias
    WHERE rownumber <= 10;
    

    Now we just have to add a GROUP BY playername and get the greatest result. So your final query is this:

    SELECT name, MAX(score) FROM (
    SELECT 
    games.game_id,
    `games`.`score`,
    CONCAT(`users`.`full_name`) AS `name`,
    `users`.`facebook_id`,
    @row_num := if(@game != games.game_id, 1, @row_num + 1) AS rownumber,
    @game := games.game_id
    FROM 
    `games`
    INNER JOIN users ON `games`.`user_id`=`users`.`id` 
    , (select @row_num := 1, @game := NULL) variables
    WHERE 
    `users`.`id` IN ('user ids goes here') 
    AND `games`.`status`=2
    ORDER BY 
    games.game_id, /*or something*/
    `games`.`score` DESC 
    ) subquery_alias
    WHERE rownumber <= 10
    GROUP BY `name`