Classificação dentro de Django ORM ou SQL?
-
22-09-2019 - |
Pergunta
Eu tenho uma lista enorme classificada por vários valores (por exemplo, pontuações)
Então eu pego a lista encomendada por esses valores:
players = Player.objects.order_by('-score', '-karma')
Eu gostaria de:
- Pegue um jogador e pegue o jogadores vizinhos
Pontuação P1: 123
Pontuação p2: 122
VOCÊS! pontuação:110
P3 Pontuação: 90
Pontuação p2: 89
- Pegue o posição!
Você está classificado como #1234 para pontuação
Você está classificado como #9876 para o karma
A ajuda seria muito apreciada. obrigado :)
Solução
Para obter a classificação do usuário:
(SELECT * FROM (
SELECT
RANK() OVER (ORDER BY Score desc ,Karma desc) AS ranking,
Id,
Username,
Score, karma
FROM Players
) AS players_ranked_by_score
where Id = id_of_user
Onde id_of_user é o parâmetro que contém o ID do jogador atual. Para conseguir os jogadores vizinhos e o usuário atual:
(SELECT * FROM (
SELECT
RANK() OVER (ORDER BY Score desc ,Karma desc) AS ranking,
Id,
Username,
Score, karma
FROM Players
) AS all_players_ranked
where ranking >= player_ranking - 2 and ranking <= player_ranking + 2;
Onde Player_ranking é o ranking obtido da consulta acima.
Espero que ajude!
Atualizar: MySQL não possui uma função de classificação () (MS SQL, Oracle, Postgres tem uma). Olhei em volta e recebi esse link explicando como fazer a classificação no MySQL: http://www.artfulsoftware.com/infotree/queries.php?&bw=1024#460.
Outras dicas
Esse tipo de coisa é sempre muito difícil de fazer. Você precisará de várias consultas para cada uma.
Então, para obter os jogadores antes e depois da sua posição, quando encomendados por pontuação, primeiro você precisará descobrir qual é essa posição. (Observe que isso pressupõe que você não pode ter mais de uma pessoa com a mesma pontuação, o que pode não ser necessariamente verdadeiro.)
me = Player.objects.get(pk=my_pk)
position = Players.objects.all().filter(
score__lte=me.score).order_by('-score').count()
players = Players.objects.all()[position-2:position+2]
Fiz isso com 3 consultas com o ORM, mas acho que menos contagem de consultas seria melhor:
user_rank = Score.objects.filter(high_score__gt=user_score.high_score).count() + 1
neighbour_scores = Score.objects.filter(game_id=gme,~Q(user_id = usr),high_score__gte=user_score.high_score).order_by('high_score')[:offset]
neighbour_scores.append(user_score)
neighbour_scores.append(Score.objects.filter(game_id=gme, high_score__lt=user_score.high_score).order_by('-high_score')[:offset])