Christian D: SQL-Datenbank für Rennergebnisse erstellen

Hallo zusammen, ich erstelle die Rennergebnisse eines Slotracing-Clubs. Das passiert momentan mithilfe von Excel und gewöhnlichen Html-Tabellen. Langfristig möchte ich jedoch auf eine Datenbank umsteigen. Bin noch recht unerfahren in der Webentwicklung und habe daher so meine Probleme mit der Erstellung der benötigten Tabellen in phpMyAdmin.

Es existiert eine Tabelle mit den Fahrern, diese haben natürlich eine eindeutige ID.

Nun möchte ich für jede Rennserie die gefahren wird eine Tabelle anlegen in der die Ergebnisse per Formular über eine Webseite eingetragen wird. Benötigt werden für jedes Rennen:

  • FahrerID (aus Tabelle 'Fahrer')
  • Runden
  • Zeit
  • Position
  • Punkte (errechnen aus Position)
  • Datum des Rennens
  • Welcher Lauf (Lauf 1, Lauf 2...)

Trotz intensivem Googlen komme ich da nicht so recht weiter wie ich das am besten umsetze. Mangelt sehr wahrscheinlich auch noch am Verständnis.

Geplant ist später dass ich aus der Tabelle einen View für jedes Rennen erzeuge und dieses dann als Tabelle in die Homepage einfüge. Oder eben per PHP die Abfrage so gestalte dass ich mir immer die gerade benötigten Daten ziehen kann.

Die Tabellen auf der Homepage sehen zurzeit so aus: https://slotters-paradise.de/dsc.html

Über Hilfe wäre ich echt dankbar!

  1. Hallo Christian,

    der erste Schritt ist die Datenmodellierung in einem Entity-Relationship Modell. Eine Entity (deutsch: Entität) ist ein Objekt in deinem System, die sich typischerweise durch einen Schlüssel und weitere Attribute auszeichnet. Ein Relationship ist eine Beziehung zwischen Entitäten. In der Modellierung werden Beziehungen immer zwischen zwei Entitäten dargestellt. Wenn es sich herausstellt, dass eine Beziehung zwischen mehr als 2 Entitäten benötigt wird, setzt man eine Verknüpfungsentität dazwischen.

    Bei Beziehungen ist die sogenannte Kardinalität wichtig. Das ist die Anzahl der Entitäten, die auf den Seiten einer Beziehung stehen können. Beispielsweise besteht zwischen einem Rennen und dem Lauf eines Rennens eine 1:N Beziehung. Zu einem Rennen gehören mehrere Läufe.

    Die Beziehung zwischen Fahrer und Lauf ist dagegen eine M:N Beziehung. Ein Fahrer kann an beliebig vielen Läufen teilgenommen haben oder noch teilnehmen. An einem bestimmten Lauf nehmen mehrere Fahrer teil.

    Vermutlich hast Du auch eine M:N Beziehung zwischen Fahrer und Rennen, die die Anmeldung eines Fahrers für ein bestimmtes Rennen darstellt und aus der die Teilnahme an allen Läufen dieses Rennens folgt. Das weiß ich aber nicht, das ist spezifisch für deine Problemstellung. Meldet man sich für einen Lauf an? Oder für ein Rennen, und startet dann in allen Läufen?

    Es gibt auch so etwas wie 1:1 Beziehungen, die sind aber meist technischer Natur (wenn z.B. eine Entität eine Gruppe von Attributen hat, von denen entweder alle oder keins gebraucht werden, kann man diese Attribute in eine Extratabelle auslagern und damit Speicher sparen. Diese Attributgruppe könnte auch andere Zugriffsberechtigungen erfordern und deshalb in eine eigene Tabelle kommen).

    Bei Dir sehe ich die Entitäten Fahrer, Rennen und Lauf. Dazu kommt auf jeden Fall eine M:N Beziehung Fahrer_Lauf (für die Zeit in einem Lauf). Ggf. gibt es eine M:N Beziehung Fahrer_Rennen (habe ich oben erklärt). Und ganz sicher gibt es eine 1:N Beziehung Rennen_Lauf.

    Eine 1:N Beziehung realisiert man so, dass man in der Entität der N-Seite die ID der 1-Seite speichert. In einem Lauf speicherst Du also die ID des Rennens, zu dem er gehört. Man nennt das einen Fremdschlüssel. In manchen Fällen kann ein Fremdschlüssel auch aus mehreren Feldern zusammengesetzt sein.

    Eine M:N Beziehung kann man in einer relationalen Datenbank nur mit Hilfe einer Zwischentabelle realisieren, in der die Fremdschlüssel von beiden Seiten gespeichert werden. Das schadet aber nichts, weil es ja für jede Paarung Fahrer und Lauf auch eigene Attribute gibt.

    Die Frage, wo Attribute wie "Datum", "Rundenzahl", "Zeit", "Position" und "Punkte" hingehören, muss man nun Attribut für Attribut untersuchen. Wenn ich ein Attribut auf der N-Seite einer 1:N Beziehung anordne, muss ich mich immer fragen: haben alle Datensätze der N-Seite, die den gleichen Wert für den Fremdschlüssel aufweisen, den gleichen Wert? Ist es beispielsweise in einem Rennen so, dass alle Läufe die gleiche Rundenzahl aufweisen? Wenn ja, gehört die Rundenzahl zum Rennen, nicht zum Lauf.

    Eine andere Frage ist, ob man bestimmte Attribute speichern muss. Beispielsweise brauchst Du die Position nicht zu speichern, sondern kannst sie durch Sortieren der Fahrer eines Laufs nach ihrer Zeit gewinnen, und damit auch die Punkte. Diese Informationen zu speichern ist aus Sicht des fachlichen Datenmodells also unnötig (redundant).

    Es ist aber so, dass Redundanzen die Schmiere der Datenbank sind. Zum einen macht man sich daran die Finger schmutzig (weil man mehr Arbeit hat, um sie aktuell zu halten), man kann darauf ausrutschen (wenn man dabei was falsch macht), aber die Datenbank flutscht auch besser (Zugriffe können schneller werden). Jede Redundanz muss wohlüberlegt sein. In deinem Fall würde ich Position und Punktezahl nicht ständig neu berechnen, sondern an der Beziehung Fahrer_Lauf speichern.

    Es scheint also sinnvoll, für dein Datenmodell 4 bis 5 Tabellen zu verwenden.

    • Fahrer (ID, Name, eMail, ...)
    • Rennen (ID, Name, Anzahl Runden, ...)
    • Lauf (ID, RennenID, Datum, ...)
    • Fahrer_Rennen(FahrerID, RennenID, ...)
    • Fahrer_Lauf(FahrerID, LaufID, RennenID, Zeit, Position, Punkte)

    Die RennenID ist in der Fahrer_Lauf Tabelle eigentlich unnötig, weil man sie über die Beziehung Rennen_Lauf rückgewinnen kann. Das ist wieder eine Redundanz, deren Nutzen man abwägen muss.

    Einen View pro Rennen würde ich NICHT erzeugen. Du musst unterscheiden zwischen der Modellierung einer DB und der Pflege ihrer Inhalte. Ein View gehört zum Modell, das Anlegen eines Rennens ist Inhalt. Wenn Du bei Pflege der Inhalte etwas am Modell ändern musst, ist das falsch. Wenn Du für eine Abfrage Tabellen- oder Spaltennamen dynamisch generieren musst, ist das meistens auch falsch. Eine Ausnahme für den letzten Satz ist deine Anzeige des Tabellenstandes. Dies ist eine Pivot-Tabelle, wo Zeilen und Spalten basierend auf DB-Inhalten aufgebaut werden. So etwas kann man direkt im SQL lösen (Pivotabfrage, die von MYSQL ab Version 8 unterstützt wird), es ist aber meistens einfacher, das programmatisch zu lösen (also im PHP Code).

    Einen View kannst Du beispielsweise für die Teilnahme eines Fahrers an Läufen erzeugen:

    CREATE VIEW laufteilnahme
      SELECT f.ID as FahrerID, l.ID as LaufID, l.RennenID
             f.Name, l.Datum, l.Zeit, l.Position, l.Punkte
      FROM fahrer f JOIN fahrer_lauf fl ON f.ID=fl.FahrerID
                    JOIN lauf l ON l.ID=fl.LaufID
    

    Was du dann nutzen könntest für alle absolvierten Läufe der Teilnehmer des Rennens mit ID 4711

    SELECT FahrerID, LaufID, Name, Datum, Zeit, Position, Punkte
    FROM laufteilnahme
    WHERE RennenID=?
    

    Für das ? setzt Du die gewünschte Renn-ID ein. Entweder gleich beim Erzeugen des Query-Strings (dann den Kontextwechsel beachten), oder durch gebundene Parameter in mysqli oder PDO.

    Hoffe, dass Du damit einen Schritt weiterkommst.

    Rolf

    --
    sumpsi - posui - clusi
    1. Hallo Rolf, danke für die sehr ausführliche Antwort.

      zugegeben, ganz verstanden habe ich es nicht. Es könnte auch sein dass meine Fragestellung etwas irreführend war.

      Ein Rennen ist in sich abgeschlossen.

      Beispiel anhand einer Rennserie: Es gibt 6 Rennen im Jahr aus denen sich dann eine Meisterschaftstabelle nach Punkten bildet. Dabei wird ein Ergebnis von 6 gestrichen. Für jedes Rennen gibt es 3 Bonuspunkte und zusätzlich Punkte für die erreichte Position.

      Kleines Beispiel! Max Mustermann fährt alle 6 Rennen mit und erhält somit 6x3 Bonuspunkte. Also 18 Punkte. Er ist bei allen Rennen erster geworden und erhält somit 6x30 Punkte. Davon wird ein Ergebnis nicht gewertet, also 5x30 Punkte, dazu kommen die 18 Bonuspunkte für die Teilnahme. Das sind insgesamt 168 Punkte.

      Nun nochmal zur Datenbank. Ich hatte mir das so vorgestellt dass ich alle 6 Rennen in einer einzigen Tabelle speichere und dann per SQL nur die Zeilen heraus hole die ich zum Beispiel für Rennen 1 im Jahr 2019 benötige. Was an sich ja kein Problem darstellt wenn ich eine Spalte habe in der beschrieben ist um welches Rennen es sich handelt und welches Jahr, bzw um welches Datum.

      Dann kann ich ja bei der Abfrage angeben dass er nur Datensätze holen soll die ein bestimmtes Datum haben und diese zum Beispiel nach Runden sortieren. Schon habe ich eine Ergebnistabelle in richtiger Reihenfolge die ich dann als HTML mittels php aufbereiten kann. So könnte ich dass dann nicht nur für bestimmte Rennen sondern auch für andere Statistiken nutzen. Zum Beispiel könnte ich mir anzeigen lassen welcher Fahrer in welchem Jahr die meisten Runden hatte, etc... (Zukunftsmusik)

      Für die Platzierung im Rennen php zu nutzen macht Sinn. Aber wie sieht es mit den Punkten aus? Wenn ich diese in der Tabelle mit angebe muss ich zwar nichts berechnen, aber spätestens bei der Meisterschaft wo ja ein von 6 Ergebnissen gestrichen wird komme ich nicht weiter. Hat zum Beispiel jemand nur an 5 Rennen teilgenommen wird nichts gestrichen da ja nur die 5 besten Rennen gewertet werden. Hat jemand an allen 6 Rennen teilgenommen wird das schlechteste Ergebnis gestrichen. Sollte ich dass dann alle per php berechnen?

      Fragen über Fragen über fragen...

      1. Hallo Christian,

        habe gerade kaum Zeit... bitte definiere deine Begriffe exakt, am besten gleich lautend zu deiner Website.

        vor allem: Rennserie, Rennen, Lauf

        Dein Projekt schreit nach einer normalisierten Datenbank. Eine Tabelle reicht nicht. Eine Datenbank ist etwas anderes als Excel!

        Möglich, dass man die Streichergebnisse mit der LIMIT Klausel von MySQL in den Griff bekommt. Dazu müsste ich mir noch mal anschauen, ob man GROUP BY und LIMIT dafür passend kombinieren kann.

        Rolf

        --
        sumpsi - posui - clusi
      2. Hallo Christian D,

        Fragen über Fragen über fragen...

        Du solltest zunächst versuchen, ein ERM zu erstellen. Für einen allerersten Überblick kann man vielleicht dieses Video anschauen.

        Bis demnächst
        Matthias

        --
        Pantoffeltierchen haben keine Hobbys.
        ¯\_(ツ)_/¯
        1. Hallo Matthias,

          jupp. So wie ich schon heut Nachmittag schrub... 😉

          Rolf

          --
          sumpsi - posui - clusi
          1. Hallo Rolf B,

            jupp. So wie ich schon heut Nachmittag schrub... 😉

            Jupp. Und ob der Ausführlichkeit von mir mit einem Plus versehen …

            Bis demnächst
            Matthias

            --
            Pantoffeltierchen haben keine Hobbys.
            ¯\_(ツ)_/¯