hmm: Ranking und Punkte

Ich wollte verschiedene Punkteverteilungen anlegen, die dann Leute für verschiedene Platzierungen bekommen sollten. Da einige Events wichtiger als andere sein sollen, wollte ich Punktekategorien machen.

Ich habe dazu eine Tabelle mit id, titel (bzw. Beschreibung) und den Platzierungen 1-16 angelegt. Jetzt will ich, dass für die Anzahl der Felder dort ein Input Feld zum Eintragen der verschiedenen Punkte erscheint.

if ($_GET['action']=="new") {  
  
            $select = ("SELECT id,title,1st,2nd,3rd,4th,5th,6th,7th,8th,9th,10th,11th,12th,13th,14th,15th,16th FROM pointcategory");  
            $query = mysql_query($select);  
            while ($ds = mysql_fetch_object($query)) {  
            $id = $ds -> ID;  
            $title = $ds -> title;  
            echo "<input name=\"".$id."" type="text" id="".$id."" class="Feld" size="20" maxlength="16">";  
            }  
        } 

Ich weiß, dass es oben mit dem Select nicht ganz stimmen kann, aber mir ist jetzt nicht eingefallen wie es sonst praktisch ist. Vielleicht hat ja jemand ne Idee, ob eine andere Tabellenstruktur günstiger geeignet ist.

Ich denke nämlich, dass es einfacher, bzw. automatischer ist das ganze automatisch erstellen zu lassen als 16 Punktefelder und 1 Beschreibungsfeld zu erstellen.

Außerdem würde ich gerne wissen, wie ich die Ranking Tabelle am besten anlege. Eigentlich sollte auf jedes Ergebnis zugreifbar sein, da ich daraus ein paar Statistiken entwerfen möchte.

Ein Event besteht nämlich aus zwei gespielten Runden, die jeweils ein Ergebnis hervorrufen aus welchem dann ein gesamt Ergebnis errechnet wird.

  1. Hi, in der Tat ist dein jetziges Tabellenschema nicht wirklich "mega"-optimal. Hier mal vielleicht ein paar Denkanstoesse:

    • die einzelergebnisse aus den "2 Runden" sind dir bekannt und bleiben statisch
    • du kannst pro Event eine Liste aus allen Teilnehmern mit ihren Ergebnissen erstellen, sortiert nach den Ergebnissen der einzelnen teilnehmer
    • zur einfacheren weiterverarbeitung solltest du dann den Rang pro Event zurueck in die Datenbank schreiben, das kannst du beim Eintragen neuer Ergebnisse einfach als zusaetzlichen Schritt wiederholen
    • zur Gewichtung fuer jeden Event fuehrst unterschiedliche Maximalpunktzahlen ein
    • alles was du mit geringem Aufwand aus bestehenden Daten berechnen kannst, brauchst du nicht speichern
    • dein DBMS (mysql) kann dir u.U. mit spezifischen Funktionen behilflich sein

    Ciao, Frank

    1. Hi, in der Tat ist dein jetziges Tabellenschema nicht wirklich "mega"-optimal. Hier mal vielleicht ein paar Denkanstoesse:

      • die einzelergebnisse aus den "2 Runden" sind dir bekannt und bleiben statisch
      • du kannst pro Event eine Liste aus allen Teilnehmern mit ihren Ergebnissen erstellen, sortiert nach den Ergebnissen der einzelnen teilnehmer
      • zur einfacheren weiterverarbeitung solltest du dann den Rang pro Event zurueck in die Datenbank schreiben, das kannst du beim Eintragen neuer Ergebnisse einfach als zusaetzlichen Schritt wiederholen
      • zur Gewichtung fuer jeden Event fuehrst unterschiedliche Maximalpunktzahlen ein
      • alles was du mit geringem Aufwand aus bestehenden Daten berechnen kannst, brauchst du nicht speichern
      • dein DBMS (mysql) kann dir u.U. mit spezifischen Funktionen behilflich sein

      Ciao, Frank

      Erstmal danke für die Antwort.

      Müsste ich dann für jedes Event eine neue Tabelle anlegen? Ansonsten kann man doch schlecht den Benutzernamen und die dazugehörigen Punkte aller in einer Tabelle abspeichern. Oder könnte man dieses eventuell mit serealize machen?

      Was mir auch einfällt ist, dass es verschiedene Divisionen gibt, welche so gut wie unabhängig voneinander sind. Ist es dann wohl dafür am besten, eine eigene Tabelle anzulegen, oder wenn es mit serealize klappt einfach den Typ der Division als eine Spalte in der Tabelle Ranking anzulegen?

      Die Statistiken hatte ich dann auch geplant aus den Ergebnissen zu berechnen. Ich dachte an simple Dinge wie Durchschnittsrang und Anzahl der Eventsiege. Das sollte ja ziemlich leicht zu errechnen sein.

      1. Hi,
        was ist "serealize"?

        Ein Grundsatz fuer "vernuenftiges" relationales Datenbankdesign: Entitaeten (Daten), die gleiche Struktur haben, gehoeren in dieselbe Tabelle.

        Also nix mit fuer jedes Event eine neue Tabelle. Sondern eine Tabelle fuer die Entitaet "Event". Jedes Event ist durch eine eindeutige Id gekennzeichnet. Diese Id verwendest du dann in einer anderen Tabelle, z.b. "Ergebnis", Ergebnis wuerde an der Stelle aus zb. 3 Spalten bestehen: Event, Spieler, ErgebnisPunktzahl. Plus evt. weitere Schluesselfelder.

        Dein Problem mit den "Divisionen" loest du am besten dadurch, dass du mal aufzeichnest, von welchen anderen Entitaeten in deiner Welt die Entitaet "Division" abhaengt und vice versa. Danach verfahre nach oben beschriebenen Schema (auch bekannt als Normalisierung).

        Die Berechnungen von Statistiken werden einfacher, wenn du gleichfoermige Daten an der selben Stelle verfuegbar hast, dann kannst du einfach Aggregatsfunktionen (wie SUM, AVG, MIN, MAX, COUNT) deines DBMS with WHERE Klauseln zusammen auf deine Daten anwenden.

        Ciao, Gruesse aus LA
        Frank

        1. Hi,
          was ist "serealize"?

          Ein Grundsatz fuer "vernuenftiges" relationales Datenbankdesign: Entitaeten (Daten), die gleiche Struktur haben, gehoeren in dieselbe Tabelle.

          Also nix mit fuer jedes Event eine neue Tabelle. Sondern eine Tabelle fuer die Entitaet "Event". Jedes Event ist durch eine eindeutige Id gekennzeichnet. Diese Id verwendest du dann in einer anderen Tabelle, z.b. "Ergebnis", Ergebnis wuerde an der Stelle aus zb. 3 Spalten bestehen: Event, Spieler, ErgebnisPunktzahl. Plus evt. weitere Schluesselfelder.

          Dein Problem mit den "Divisionen" loest du am besten dadurch, dass du mal aufzeichnest, von welchen anderen Entitaeten in deiner Welt die Entitaet "Division" abhaengt und vice versa. Danach verfahre nach oben beschriebenen Schema (auch bekannt als Normalisierung).

          Die Berechnungen von Statistiken werden einfacher, wenn du gleichfoermige Daten an der selben Stelle verfuegbar hast, dann kannst du einfach Aggregatsfunktionen (wie SUM, AVG, MIN, MAX, COUNT) deines DBMS with WHERE Klauseln zusammen auf deine Daten anwenden.

          Ciao, Gruesse aus LA
          Frank

          Ui, ich hoffe LA ist schön :)

          Ups, hatte es falsch geschrieben. Meinte serialize (http://www.nak-webmaster.de/modules.php?name=News&file=article&sid=61).

          Da ich relativ neu bin in PHP, muss ich mir erstmal klarmachen, wie das dann alles zusammenhängt. Also einmal die Tabelle "Event". Diese würde dann die eventID haben.
          In einer weiteren Tabelle würden dann zum Beispiel alle Ergebnisse zu diesem Event drinnenstehen, also "Ergebnis" - wie du bereits gesagt hast - mit den Spalten 'Event, Spieler, Ergebnis1, Ergebnis2, Gesamtergebnis'. Könnte man dann nicht für die ID einen Fremdschlüssel zur eventID aus der Tabelle "Event" machen?
          Ich glaube, womit ich grade etwas stutzig werde ist, wie ich dann die Ergebnisse jedem Spieler zuordne. Also kann man denn mehrere Spieler in einer Spalte 'Spieler' eintragen wofür jeder seine zugehörigen Punkte hat, sodass man diese auch wieder auslesen kann. Ich dachte nämlich bisher, dass man dann für jeden Spieler eine neue Zeile bräuchte, damit die Punkte irgendwie nicht durcheinander geraten.

          In "Divisionen" hätte ich 'divID, divCATEGORY, divTYPE, divDESCRIPTION'. Man muss sagen, dass ich jede Division nach Spielart nochmals unterteilen würde.

          1. Danke der Nachfrage, LA ist heute grad ziemlich warm (draussen zumindest) ... aber bin bis abends um 9 hier im Conference Center, da hab ich nicht viel davon. :(

            Also, nochmal zu deinem Problem. PHP ist eine Sache, Datenbankdesign eine andere. Dein Problem ist nicht PHP im Moment, sondern Datenbankdesign.

            Fragen, die du dir fuer ein properes Design beantworten solltest:

            • welche Entitaeten gibt es
                - Spieler
                - Event
                - Spiel
                - Division
                - Ergebnis
            • welche Beziehung haben
                - Event zu Spiel (1:n)
                - Spieler zu Ergebnis (m:n)
                - usw.

            Dort, wo du 1:n Beziehungen hast, hast du in der Tabelle (fuer n) einen Fremdschluessel auf die Elterntabelle. Fuer m:n Beziehungen brauchst du eine eigene Tabelle mit Fremdschluessel-Spalten fuer n und m.

            Z.b. die Tabelle, wo du die Ergebnisse speicherst, hat 1 Record pro

            • Spieler
            • Spiel
            • Runde
              (- Event)
              plus genau _eine_ Spalte fuer das Ergebnis (und nicht 3).

            Mit Fremdschluesseln lagst du also schon etwa richtig.

            Und bitte niemals mehrere Werte innerhalb einer einzigen Zelle (Zeile/Spalte) speichern, so a la "23, 24, 25" ;-)

            Ciao, Frank

            1. Danke der Nachfrage, LA ist heute grad ziemlich warm (draussen zumindest) ... aber bin bis abends um 9 hier im Conference Center, da hab ich nicht viel davon. :(

              Also, nochmal zu deinem Problem. PHP ist eine Sache, Datenbankdesign eine andere. Dein Problem ist nicht PHP im Moment, sondern Datenbankdesign.

              Fragen, die du dir fuer ein properes Design beantworten solltest:

              • welche Entitaeten gibt es
                  - Spieler
                  - Event
                  - Spiel
                  - Division
                  - Ergebnis
              • welche Beziehung haben
                  - Event zu Spiel (1:n)
                  - Spieler zu Ergebnis (m:n)
                  - usw.

              Dort, wo du 1:n Beziehungen hast, hast du in der Tabelle (fuer n) einen Fremdschluessel auf die Elterntabelle. Fuer m:n Beziehungen brauchst du eine eigene Tabelle mit Fremdschluessel-Spalten fuer n und m.

              Z.b. die Tabelle, wo du die Ergebnisse speicherst, hat 1 Record pro

              • Spieler
              • Spiel
              • Runde
                (- Event)
                plus genau _eine_ Spalte fuer das Ergebnis (und nicht 3).

              Mit Fremdschluesseln lagst du also schon etwa richtig.

              Und bitte niemals mehrere Werte innerhalb einer einzigen Zelle (Zeile/Spalte) speichern, so a la "23, 24, 25" ;-)

              Ciao, Frank

              Oh, hoffentlich kannst du es dann immerhin am Tag genießen.

              Also kann man sagen, dass Event zu Spiel die Beziehung 1:n hat, weil es viele Events gibt, aber nur ein Spiel.
              Aber Spieler zu Ergebnis ist m:n, weil es viele Spieler gibt und auch viele dazugehörige Ergebnisse.

              Record heißt Zeile?

              Was ich dann nicht ganz verstehe ist, wie ich dann in der Tabelle Ergebnisse mit Spieler, Spiel, Runde, Event und Ergebnis drei verschiedene Ergebnisse eintragen kann, obwohl es nur eine Spalte ist. Na gut, die dritte könnte man ja immer berechnen lassen, aber die zweite?
              ----> Ach, natürlich, Runde 2 würde dann das zweite Ergebnis beinhalten. Und das Gesamtergebnis tut man dann in eine extra dritte Runde?

              1. Hi, bitte nicht immer alles nochmal zitieren. Das muellt nur den Server voll.

                Ja, Record == Zeile == Datensatz

                Wenn du jetzt eine Tabelle hast fuer "alles auf einmal" ...

                +------------|------------|------------|------------|------------------+
                | Spieler  |  Event  | Spiel    |  Runde |  Ergebnis   |
                +------------|------------|------------|------------|------------------+
                |  1         |  1         |  1        |  1        |  10            |  *
                |  2         |  1         |  1        |  1        |   0             |
                |  1         |  1         |  1        |  2        |   5             |  *
                |  2         |  1         |  1        |  2        |  20            |
                |  25       |  2         |  2        |  1        |  10            |  **
                |  26       |  2         |  2        |  1        |   0             |

                * du brauchst 1 Datensatz pro Spieler, Event, Spiel und Runde, also fuer komplettes Ergebnis 4 Datensaetze 2 Spieler x 2 Runden

                ** wenn du nun nur 1 Runde pro Spiel hast, brauchst du nur 2 Datensaetze, bei 10 Runden und 3 Spielen dann 30 Datensaetze

                Das Gesamtergebnis ergibt sich dann als SUM(Ergebnis) GROUP BY Spieler, Spiel, Event

                Das kannst du in einer "View" mit UNION ALL (und einem Wert von -1 fuer Runde) hinten dran haengen.

                Mit einem Self-Join kannst du pro Spiel, Event und Runde den Gewinner ermitteln mit einer einfachen -(Minus) Operation.

                Gruss, Frank

                1. Habe gedacht, dass ist wichtig, damit die Antwort auch zum richtigen Thema kommt. Das Design ist ungewöhnlich für Foren ;)

                  Also das finde ich alles einleuchtend. Aber habe noch eine Frage, warum man -1 dann dranhängen muss.

                  Auf jeden Fall schonmal danke für die Hilfe.

                  1. Hi,

                    -1 Fuer das Gesamtergebnis, meinst du? Naja, du wirst nie eine Spielrunde -1 haben, aber Spielrunden 2, 3 vielleicht auch 5 oder 10. -1 ist insofern ein Surrogatwert (Ersatzwert) fuer den "Gesamtwert". Wenn du nur die Gesamtwerte sehen willst, notierst du in deinem SQL  WHERE Runde = -1, wenn du nur die Ergebnisse von realen Spielrunden sehen willst, dann WHERE Runde > 0 ... und so weiter.

                    Dieses Forum hier ist in mancher hinsicht etwas spezieller. Zitieren darfst du schon, aber am besten genau und nur die Stellen auf die du dich beziehst. Aller Text deines Postings wird gespeichert, auch das, was du zitierst. Das heisst, es wuerde quasi jedes Posting doppelt gespeichert. Weitere Infos dazu findest du auch in der "Charta" des Forums (mal ein selten doofer Name fuer FAQ), welche auf der Forumshauptseite verlinkt ist

                    Gruss, Frank

                    1. Ciao,

                      also habe ich dann insgesamt doch drei Zeilen für einen Spieltag?

                      +------------|------------|------------|------------|------------------+
                      | Spieler  |  Event  | Spiel    |  Runde |  Ergebnis   |
                      +------------|------------|------------|------------|------------------+
                      |  1         |  1         |  1        |  1        |  10            |
                      |  1         |  1         |  1        |  2        |   5             |
                      |  1         |  1         |  1        |  -1        | SUM(Ergebnis)  |

                      1. nein, nicht unbedingt, die 3. Zeile kannst du dynamisch generieren ...

                        Mein Hinweis beruhte auf der Erstellung eines Datenbankobjekts vom Typ VIEW, welche mittels UNION ALL mehrere Ergebnismengen (erst die echten Daten und dann die kalkulierten im selben Format) aneinanderhaengt. Fuer so ein UNION benoetigst du gleichfoermige SELECTs, sprich dieselbe Menge an Spalten mit identischen Typen. Deshalb musst du fuer die Gesamtergebnisse (hintendran) auch einen Wert fuer die Spalte "Runde" geben: -1 .... ja, NULL tut es auch ;)

                        Cheers, Frank

                        1. CREATE VIEW Gesamtergebnis AS
                            SELECT spieler,event,ergebnis,spiel,runde
                            FROM   ergebnisse
                            UNION ALL
                            SELECT spieler,event,ergebnis,spiel,runde
                            FROM ergebnisse

                          hm, du merkst, ich habe bisher noch nie mit UNION ALL gearbeitet. Also ich würde jetzt ein VIEW erstellen, der spieler, event, ergebnis, spiel und runde aus den Ergebnissen rausholt. Doch das was nach dem UNION ALL kommt, weiß ich jetzt nicht ganz. Muss dann da ein WHERE runde="-1"?

                          1. Morgen :)

                            also .... machen wir mal ein paar speibiele ....

                              
                            -- eine view fuer nur die gesamtergebnisse  
                            CREATE VIEW GesamtErgebnisse AS  
                               SELECT spieler, event, spiel, SUM(ergebnis)  
                               FROM ergebnisse  
                               GROUP BY spieler, event, spiel  
                              
                              
                            -- eine view fuer alle ergebnisse inklusive gesamt ergebnisse  
                            CREATE VIEW GesamtErgebnisse AS  
                               SELECT spieler, event, spiel,  
                                             runde,  
                                             ergebnis,  
                                             0 AS IstGesamtErgebnis  
                                 FROM ergebnisse  
                               UNION ALL  
                               SELECT spieler, event, spiel,  
                                             NULL AS runde,                       -- diese spalte ist notwendig fuer das UNION ALL, kann man auf NULL setzen oder -1 oder -2  
                                             SUM(ergebnis) AS ergebnis,     -- eine einfache arithmetische Summe der Ergebnisse  
                                             1 AS IstGesamtErgebnis          -- ein optionales bit-flag  
                               FROM ergebnisse  
                               GROUP BY spieler, event, spiel  
                              
                            -- eine view fuer gesamt- und durchschnittliche ergebnisse  
                            CREATE VIEW GesamtErgebnisse AS  
                               SELECT spieler, event, spiel,  
                                             "Gesamtergebnis" AS ergebnistyp,  
                                             SUM(ergebnis) AS ergebnis     -- eine einfache arithmetische Summe der Ergebnisse  
                                 FROM ergebnisse  
                                 GROUP BY spieler, event, spiel  
                               UNION ALL  
                               SELECT spieler, event, spiel,  
                                             "Durchschnitt" AS ergebnistyp,  
                                             AVG(ergebnis) AS ergebnis     -- eine einfache arithmetische Summe der Ergebnisse  
                                 FROM ergebnisse  
                                 GROUP BY spieler, event, spiel  
                            
                            

                            Du siehst, es gibt ne ganze menge Moeglichkeiten fuer Ergebnisse.

                            Cheers, Frank

                            1. Danke, dass macht es klar :)

                              A propos, da ich ja wie im ersten Beitrag beschrieben, auch verschiedene Punkteverteilungen machen wollte, denke ich, dass es doch wohl am einfachsten mit einer Tabelle "Punktekategorien" geht, wo jeweils die Spalten 1-16 als die Platzierung und die dazugehörigen Punkte und eine Beschreibung der Punkteverteilung reinkommt.

                              Ich möchte jetzt ein Admin Menü kreiiren, indem man die Punkte für jeden Platz eintragen kann. Dropdown per while habe ich schon oft benutzt, aber ich stolpere momentan über das mit einem Input Feld, falls das überhaupt geht.

                              SELECt * FROM punktekategorien ist denke ich am einfachsten, da sich ja eventuell die Anzahl der Plätze ändern kann.
                              Doch wie mache ich es am besten, dass für jede Spalte ein Input Feld mit type="text" entsteht?

                              1. SELECt * FROM punktekategorien ist denke ich am einfachsten, da sich ja eventuell die Anzahl der Plätze ändern kann.
                                Doch wie mache ich es am besten, dass für jede Spalte ein Input Feld mit type="text" entsteht?

                                Genau das ist der Punkt, wo du siehst, dass die Datenorganisation in "Spalten" fuer solche Zwecke total ungeeignet ist.

                                Die Punktekategorie ist abhaenging wovon? Event, Spiel, Event und Spiel?

                                Wenn du die Punktekategorie "so" organisierst:

                                Tabelle Punktekategorien (Id int, SpielId int, Name varchar(50))
                                Tabelle PunktekaegroriePlaetze (PunkteKategorieId int, Platz int, Punkte in)

                                Dann fuegst du pro angelegte Kategorie immer Datensaetze/Zeilen fuer jede Platzierung ein, fuer die du punkte vergeben willst. Einfaches Insert, fertig.

                                Wie schon mehrmals gesagt bzw geschrieben habe, versuche deine Daten besser vertikal (in Zeilen) statt horizontal (in Spalten) zu halten und verwalten. Das vereinfacht Aggregationen und Joins deutlich ...

                                Frank

                                1. Also ich hatte es so vor, dass zu jedem Event man per Dropdown die Punkteverteilung aussuchen kann. Meistens ist sie eh gleich, aber falls ich mal vorhaben sollte sie zu ändern, sollte man lieber jetzt so planen.
                                  Ich denke, dann braucht man die Spalte SpielID in der Tabelle Punktekategorien gar nicht.

                                  Irgendwie habe ich Probleme so zu denken, aber ich denke, dass ich es schon schaffen werde :)

                                  Wie gebe ich diese denn dann am besten ein. Ich denke, dann sollte es am besten sein, wenn man die Punkte und den Rang nacheinander eingibt, anstatt alle auf einer Seite?