2014-06-09 21 views
5

Jestem nowym użytkownikiem sql i nigdy nie użyłem zmiennych lub warunków w mysql, ale wiem, że z innych języków programowania. Od kilku dni staram się znaleźć sposób na ocenę wyniku użytkownika. Czytałem wiele artykułów, a także pytania zadawane na stackoverflow i wreszcie znalazłem rozwiązanie, które prawie robi to tak, jak tego chcę.MySQL Rank with ties

SELECT 
    score_users.uid, 
    score_users.score, 
    @prev := @curr, 
    @curr := score, 
    @rank := IF(@prev = @curr, @rank, @rank +1) AS rank 
FROM 
    score_users, 
    (SELECT @curr := null, @prev := null, @rank := 0) tmp_tbl 
WHERE 
    score_users.matchday = 1 
ORDER BY 
    score_users.score DESC 

Ale moje problemy są wyniki tie. Nie chcę, aby dostać kolejne szeregi, jak to:

+------------+------+--------+ 
| uid | name | rank | score | 
+------------+------+--------+ 
| 4 | Jon | 1 | 20 | 
| 1 | Jane | 2 | 19 | 
| 2 | Fred | 2 | 19 | 
| 9 | July | 3 | 18 | 
| 7 | Mary | 4 | 17 | 
| 3 | Toni | 5 | 12 | 
| 5 | Steve | 5 | 12 | 
| 6 | Peter | 6 | 11 | 
| 8 | Nina | 7 | 10 | 
+------------+------+--------+ 

chciałbym uzyskać wynik takiego:

+------------+------+--------+ 
| uid | name | rank | score | 
+------------+------+--------+ 
| 4 | Jon | 1 | 20 | 
| 1 | Jane | 2 | 19 | 
| 2 | Fred | 2 | 19 | 
| 9 | July | 4 | 18 | 
| 7 | Mary | 5 | 17 | 
| 3 | Toni | 6 | 12 | 
| 5 | Steve | 6 | 12 | 
| 6 | Peter | 8 | 11 | 
| 8 | Nina | 9 | 10 | 
+------------+------+--------+ 

Chyba trzeba utworzyć nową tabelę tymczasową, a niektóre jeśli warunki, ale nie mogłem znaleźć rozwiązania i stać się zdesperowanym! Muszę też mieć oko na wydajność, może są lepsze sposoby na zdobycie rangi w wynikach? Byłbym bardzo wdzięczny za wskazówki lub fragment kodu.

+0

bym generować rangę poza SQL, ponieważ łatwiej jest zrobić cokolwiek z programu używasz (ranking według wynik to wystarczy). Robienie tego, co robisz, jest skomplikowane w MySQL! – serakfalcon

Odpowiedz

3

Można użyć innej zmiennej liczyć te same szeregi więc zamiast zwiększający @rank o 1, to przyrost @rank przez wartość licznika, tak:

SELECT 
    score_users.uid, 
    score_users.score, 
    @prev := @curr, 
    @curr := score, 
    @rank := IF(@prev = @curr, @rank, @rank + @i) AS rank, 
    IF(@prev <> score, @i:=1, @i:[email protected]+1) AS counter 
FROM 
    score_users, 
    (SELECT @curr := null, @prev := null, @rank := 0, @i := 0) tmp_tbl 
WHERE 
    score_users.matchday = 1 
ORDER BY 
    score_users.score DESC 
+1

Dzięki Aziz, ten działa bardzo dobrze. Właśnie ustawiłem @rank na 1 w podsekcji, w przeciwnym razie ranking zaczynał się od 0! Twoje zdrowie – FredFus

0

Dodaj kolejne pole rangi, który jest zawsze zwiększany. Jeśli wartość pasuje do ciebie, używaj swojej istniejącej rangi (nie zwiększaj), jeśli nie, używaj zawsze zwiększanej rangi.

SELECT 
    score_users.uid, 
    score_users.score, 
    @prev := @curr, 
    @curr := score, 
    @rank1 := @rank1 + 1, 
    @rank := IF(@prev = @curr, @rank, @rank1) AS rank 
FROM 
    score_users, 
    (SELECT @curr := null, @prev := null, @rank := 0, @rank1 := 0) tmp_tbl 
WHERE 
    score_users.matchday = 1 
ORDER BY 
    score_users.score DESC 
0

W przypadku wiązań można pominąć i użyć bieżącego numeru wiersza do następnego niezmienionego wiersza wartości wyniku jako następnej wartości. Po powinny pomóc

SELECT 
    score_users.uid 
    , @curr_score := score_users.score as score, 
    , case when @prev_score = @curr_score then @rank := @rank 
     else @rank := (@curr_row + 1) -- <- this is what you require 
    end as rank 
    , @curr_row := (@curr_row + 1) as curr_row 
    , @prev_score := @curr_score 
FROM 
    score_users, 
    (SELECT @curr_score := 0, @prev_score := 0 
     , @curr_row := 0, @rank := 0) initializer 
WHERE 
    score_users.matchday = 1 
ORDER BY 
    score_users.score DESC