PHP, MYSQL - Potrzebna rada mądrzejszego z MAX GROUP BY

0

Witam Wszystkich,

potrzebuję rady kogoś mądrzejszego, bo od dwóch dni szukam po różnych forach rozwiązania, na blogach, w manualu i w żaden sposób nie mogę sobie poradzić. Mam 3 tablice przechowujące dane:

Tablica account: ac_id, auth
Tablica dle_users: user_id, name, auth_user
Tablica game: game_id, account_id, score, secondsPlayed, started

Chcę utworzyć ranking, który pokaże, który gracz zajmuje kolejno pierwsze, drugie, trzecie itd. miejsce sortując według ilość punktów (score), a w przypadku remisu - czasu gry (secondsPlayed). Kombinuję w różny sposób z podzapytaniami i tworząc pętle, ale nadal nie ma tego, co powinno być.

Poniżej ranking, który ma wyglądać następująco:
Miejsce | Gracz | Wynik | Czas
1 | Aneta | 24 | 2:07
2 | Marcin | 24 | 2:21
3 | Marek | 21 | 1:50

O ile nie ma remisu to problemu nie ma, jeśli jednak jest remis pojawia się problem z błędnym przypisywaniem czasu.

Kod zapytania MYSQL w PHP:

$i=1;
$data1 = '2013-02-17 18:03:28';
$data2 = '2013-03-17 18:03:28';
$account = mysql_query("SELECT a.*, b.*, c.*, MAX(c.score) AS wynik FROM account AS a, dle_users AS b, 
game AS c WHERE a.auth=b.auth_user AND a.ac_id=c.account_id AND c.started BETWEEN '$data1' AND '$data2'
GROUP BY c.account_id ORDER BY wynik DESC, c.secondsPlayed ASC LIMIT 5");
while( $ranking = mysql_fetch_assoc( $account ))
    {
    $seconds = $ranking[secondsPlayed];
    $min = floor ($seconds / 60);
    $sec = $seconds % 60;
    echo '<tr align="center"><td>'.$i++.'</td><td>'.$ranking[name].'</td><td>'.$ranking[wynik].'</td><td>'.$min.':';if (strlen($sec)==1){echo '0';} echo $sec.'</td></tr>';
    }

Problem w tym, że prawidłowo jest pobierany najwyższy wynik gracza w określonym przedziale daty, ale pozostałe pola rekordu nie są prawidłowo przypisywane. Czas gry (secondsPlayed), który jest w rekordzie z najwyższym wynikiem (score) już nie jest pobierany z prawidłowego pola tylko pierwszy z całej tablicy, gdzie id gracza (account_id) znajduje się.

Aby to zobrazować poniżej kawałek tablicy game:

game_id | account_id | score | secondsPlayed
1 | 4 | 8 | 101
2 | 5 | 16 | 120
3 | 4 | 24 | 127

Zapytanie pobiera prawodłowo MAX(score) jako 24 grupując po ID gracza (w przykładzie account_id = 4), ale już czas gry (secondsPlayed) zamiast 127 sekund pobiera 101. Jak zadać pytanie, aby pobierało właściwe pole?

0

Właśnie w napisaniu tego PRAWIDŁOWEGO zapytania poprosiłem o pomoc :) a., b. i c.* bo potrzebuję danych z całych tablic. Tutaj pisałem tylko o fragmencie, który jest najważniejszy. Łączenie tablic z WHERE a JOIN nie ma różnicy, bo zarówno w jednym i drugim przypadku podaje się warunki według których pól ma nastąpić łączenie. Poniższe zapytania działa także z WHERE.

Problem rozwiązałem już wczoraj wrzucając MAX(score) jako podzapytanie. Teraz bez problemu przypisuje prawidłowo całe rekordy. Gdyby ktoś miał podobny problem, podaję rozwiązanie, być może komuś się przyda.

Prawidłowe rozwiązanie używając JOIN:

SELECT a.*, c.*, d.* FROM (SELECT DISTINCT account_id, MAX(score) AS wynik FROM game GROUP BY account_id) AS b LEFT JOIN game AS a ON b.account_id = a.account_id AND b.wynik = a.score LEFT JOIN account AS c ON a.account_id = c.ac_id LEFT JOIN dle_users AS d ON c.auth = d.auth_user WHERE d.auth_user IS NOT NULL AND a.started BETWEEN '$data1' AND '$data2' ORDER BY b.wynik DESC, a.secondsPlayed ASC LIMIT 5

Prawidłowe rozwiązanie używając WHERE:

SELECT a.*, c.*, d.* FROM (SELECT DISTINCT account_id, MAX(score) AS wynik FROM game GROUP BY account_id) AS b, game AS a, account AS c, dle_users AS d WHERE b.account_id = a.account_id AND b.wynik = a.score AND a.account_id = c.ac_id AND c.auth = d.auth_user AND d.auth_user IS NOT NULL AND a.started BETWEEN '$data1' AND '$data2' ORDER BY b.wynik DESC, a.secondsPlayed ASC LIMIT 5

Pozdrawiam

0

I twierdzisz, że łączenie LEFT JOIN jest takie samo jak to we WHERE ? :)
Poza tym po co ci ten DISTINCT?
Dlaczego masz d.auth_user IS NOT NULL? (Dla WHERE w ogóle takich rekordów nie powinno być, bo tabela c je odrzuci, a dla JOIN wystarczy zmienić rodzaj JOINa)
I zrezygnuj z * - nie są potrzebne - wymień TYLKO te pola, które potrzebujesz.

1 użytkowników online, w tym zalogowanych: 0, gości: 1