0

I've got a database with 120k players. Each entry contains id, score (and more). The goal is to get a highscore-list of not the top players, but instead of the N players above and and below a player, given his ID.

I currently try to solve this using two queries.

Query 1:

SELECT (
    SELECT  COUNT(*)
    FROM    players p2
    WHERE   p2.score > p1.score
    ) AS rank
    FROM players p1
    WHERE id = ID

returns the rank RANK of the player with an offset of -1. (for the best player it'll return 0)

Query 2:

SELECT  id, score 
    FROM players
    ORDER BY score DESC
    LIMIT X OFFSET RANK;

returns a list with X=2*N+1 entries. I shift the $rank by -n to have the player that is doing the request in the middle (n players higher, current player, n players below).

So far, so good.

The actual issue now is, that for some scores there are more players with this score than X is big, which sometimes results in the player that should be in the middle of the list not even being contained in the X entries, but in some entries above or below.

To me it seems like a consistency problem, that query 1 returns a rank Y for player Z, but query 2 doesn't have player Z at it's Y'th position.

Can these queries be merged, or is there any other nice solution to this?

If the above stated is not clear, here's a minimalistic example:

n=1, requesting player called: C
database: A:123, B:123, C:123, D:123
Query 1 returns rank 3 for player C
Query 2 returns A:123, B:123, D:123 (being ranks 2-4)
C:123 should be in the middle, but the sorting of query 2 had C as rank 1.
The order of the elements with the same score in query 2 seems randomly
Strawberry
  • 33,750
  • 13
  • 40
  • 57
Tavados
  • 2,168
  • 3
  • 14
  • 27
  • **WARNING**: This has some severe [SQL injection bugs](http://bobby-tables.com/) because user data is used inside the query. Whenever possible use **prepared statements**. These are quite straightforward to do in [`mysqli`](http://php.net/manual/en/mysqli.quickstart.prepared-statements.php) and [PDO](http://php.net/manual/en/pdo.prepared-statements.php) where any user-supplied data is specified with a `?` or `:name` indicator that’s later populated using `bind_param` or `execute` depending on which one you’re using. **NEVER** put `$_POST`, `$_GET` or any user data directly in your query. – tadman Jan 02 '18 at 20:43
  • Thanks for the hint, but I'm aware of that. This isn't an exact copy of my queries or code. ;) – Tavados Jan 02 '18 at 20:47
  • When adapting for Stack Overflow try and put in things like `?` for "don't care" values or placeholders. The way you have it here with `'$id'` screams injection bug. – tadman Jan 02 '18 at 20:48
  • Hm, I used that notation to imply, that I'm doing this in a php script and to use conventional variable naming for that, but I get your point. – Tavados Jan 02 '18 at 20:50
  • You may want to look at [answers like this](https://stackoverflow.com/questions/3614666/mysql-get-row-position-in-order-by) for inspiration. It depends on how you want to handle ties as to how to implement this. Like `1,2,2,3` or `1,2,2,4`. – tadman Jan 02 '18 at 20:53

1 Answers1

-1

You can get the rank (position) in the highscore-list with something similar to the following query:

select * from (
    select @rank:=@rank+1 rank, p.id
    from players p
    order by score desc
) t, (select @rank:= 0) t2
where id = :UID

After this query you can change the outer select to only get rank in the range of "rank" +- N

Sebastian
  • 31
  • 5
  • Similar? Yes. But not the same. – Strawberry Jan 03 '18 at 01:17
  • Can you eloborate on that? When adjusting your query to my actual table, the output ist just |rank|id|@rank:=0| |NULL|UID|0| – Tavados Jan 03 '18 at 11:37
  • @Strawberry My query is just a hint in the direction of a solution. I have no create statement to write the query. For my table with my data the query is working. You can provide me a create statement and example data, and I will create the query for you. – Sebastian Jan 09 '18 at 12:56
  • @Tavados How is you table looking like? Do you have an example? And What is your query looking like after adjusting my query? – Sebastian Jan 09 '18 at 12:57