Ranking graczy w MySQL i PHP

Tworze stronę na której ma być wyświetlony ranking graczy. Obecnie mam dwie tabele z graczami i drugą z informacjami o meczach miedzy nimi. Tabele poniżej.

Tabela gracze:

gracze.jpg

Tabela fow_data z meczami:

mecze.jpg

 

Jak teraz stworzyć ranking graczy. Moje zapytanie jakie zrobiłem to:

SELECT SUM(punkty1) AS punkty1, gospodarz
FROM fow_data  
GROUP BY gospodarz ORDER BY punkty1 DESC

 

Ale to zapytanie tworzy ranking dla kolumny gospodarz nie uwzględniając gracza krzys, który był przeciwnikiem bartka i ajaxa a także zdobył punkty (punkty2).

 

Jest możliwe w ogóle  zrobienie takiego rankingu aby uwzględniał punkty i graczy z dwóch kolumn. Np gracz ajax powinien mieć 71 punkty.

Jest to możliwe, ale przy obecnie strukturze bazy danych jedynie w PHP.

Jak by to miało być zrealizowane za pomocą PHP ?

Jakich zmian musiał bym dokonać aby możliwe to było za pomocą SQL’a ? Podział na dwie tabele ?

 

Po pierwsze - da się to zrobić na poziomie zapytania MySQL - być może trzeba będzie użyć klauzuli JOIN.

Po drugie - po to masz nadane id dla graczy, żeby z nich korzystać w tabeli fow_data (trzymasz  tam id, a nie imiona graczy).

 

Chętnie zobaczę rozwiązanie na joinie, owszem da się to zrobić w samej bazie, ale tylko za pomocą stworzenia funkcji. Nie wspomniałem o tym celowo ponieważ będzie to rozwiązanie dużo trudniejsze we wdrożeniu dla autora ponieważ ledwo radzi sobie z podstawami.

 

 

W SQL trzeba by zaprojektować całą bazę danych, zastanowić się jakie dane są nam potrzebne i jakie będą gromadzone, następnie przeprowadzić proces normalizacji lub zaprojektować bazę danych od góry (projektowanie zstępujące) i wypisać wszystkie encje w bazie danych ich pola oraz wykreślić relacje jakie pomiędzy nimi zachodzą.

 

W PHP musiałbyś mieć algorytm mniej więcej taki:

  1. Utwórz zmienną suma punktów z wartością początkową 0

  2. Pobierz z tabeli gdzie gospodarz lub przeciwnik nazywa się XXX

  3. Dla każdego pobranego rekordu w pętli:

  4. a) jeśli gospodarz to XXX dodaj punkty1 do sumy punktów

  5. b) w przeciwnym wypadku jeśli przeciwnik to XXX dodaj punkty2 do sumy punktów

  6. Zwróć sumę punktów

Bazując na Podwójene złącznie z jedną tabelą w MySQL może by się udało jakoś to ogarnąć.

Wyłuskanie sumy punktów osoby występującej w obu kolumnach (gospodarz i przeciwnik) tabeli fow_data uzyskamy tak:

SELECT g.gospodarz, p1.punkty1 + p2.punkty2

FROM `fow_data` AS g

INNER JOIN `fow_data` AS p1 ON p1.gospodarz = g.gospodarz

INNER JOIN `fow_data` AS p2 ON p2.przeciwnik = g.gospodarz

Jeszcze pozostaje kwestia wypisania osób występujących tylko w jednej z tych 2 kolumn i połączenia tego w całość - być moze da się to jakoś zrobić, ale moja wiedza o MySQL nie jest zbyt duża.

 

[…] Dodatkowo dochodzi to, że nie dostajemy wyniku jaki oczekiwaliśmy oraz co jeśli jeden gracz grał w N meczach, w przykładzie mieliśmy maksymalnie 2 mecze, ale równie dobrze może być ich 100. Jeśli jakimś cudem Twoje zapytanie przeszłoby przez interpreter to mielibyśmy pokraczną listę z sumą punktów z pierwszego meczu jaki gracz odbył jako gospodarz oraz pierwszego meczu w którym był przeciwnikiem.

Kolejna kwestia jest taka że złączenia zawsze są kosztowne, a Ty proponujesz zrobić dwa do tej samej tabeli do tego złączenie nie odbywa się po indeksach tabeli czyli jest jeszcze bardziej kosztowne i czasochłonne. Efekt tego będzie taki że będziemy przetwarzać więcej danych w tymczasowej tabeli utworzonej ze złączenia pierwszego (a co tu mówić o drugim) niż jest w samej tabeli.

 

Można by to robić selectem i funkcją sum pod warunkiem że mielibyśmy dobrze zaprojektowaną bazę danych. Przy tej tabeli w grę wchodzi albo funkcja w MySQL albo oprogramowanie tego w PHP.

  1. Generalnie nie wiem po co ci w takim modelu pierwsza tabela.
  2. Jak rozumiem ranking to suma punkt1 i punkty2 w zależności od tego czy gracz jest analogicznie gospodarzem czy przeciwnikiem, więc dla ajax wychodzi na moje oko 61 , a nie 71.

Chcę, żebyś zrozumiał, że to co ci teraz podam rozwiąże twój tymczasowy problem, ale nie rozwiąże twoich głębszych problemów. Np. jeśli kiedyś będzie 2000 graczy, a ty będziesz chciał zrobić tabelkę TOP 5, która nie zarżnie bazy danych, to tego nie zrobisz. Masz błędy w podstawach projektowania baz danych.

A taki szybki fix na potrzeby wyciągnięcia całości tabeli, musisz dodać id do tabeli i zrobić tak jak ja w tym fidzie: http://sqlfiddle.com/#!9/06b54/6

id jest potrzebne bo przy unii rekordy które są duplikatami zostaną pominięte.

Możesz to zobaczyć wykonując takie zapytanie, które zwróci 5 rekordów (bartek z wiersza 1 nie różni się niczym od tego z wiersza 2):

Oczywiście to co jest tam jest bardzo, bardzo złe i nie powinno się tak robić jeśli coś piszemy na poważnie.

Nie zauważyłem ale źle dodałem obrazek z meczami tam oczywiście jest kolumna id. Jeśli miałbym identyfikatory zamiast nazw prościej byłoby utworzyć odpowiednie zapytanie czy nadal byłoby to problemem ? 

Mogę przeprojektować bazę danych aby była poprawna.

 

Nie będzie nadal tak samo trzeba zrobić jak Ci to opisałem.

 

 

Myślę że to byłoby najlepsze rozwiązanie.