Rolf B: MySQL: Erweiterte Abfrage - Sollte/darf man das so tun?

Beitrag lesen

Hallo Nico R.,

Nun kann es allerdings in einer Saison fünf verschiedene Wettbewerbstypen (Liga, Landespokal, DFB-Pokal, Testspiel, Relegation) geben. Ich möchte gerne pro Saison die jeweiligen Gesamtsummen für diese Wettbewerbe erhalten.

Das sieht doch schonmal so aus, als ob deine Query das falsche Format hätte. Du hast gar nicht so viele Spalten im Display wie die Query liefert, d.h. du musst bei deiner Query pro Saison erstmal rauskriegen, welche Spalten überhaupt gezeigt werden müssen. Ich reverse-engineere für Dich das folgende Datenmodell (sicherlich hast Du noch mehr Spalten in den Tabellen):

Ich hätte noch fachliche Fragen:

  • Das Datenmodell gibt her, dass ein Spieler am Spieltag 1 in der Oberliga spielt und am Spieltag 2 in der Kreisliga (z.B. Ausleihe). Bist Du auf diesen Fall vorbereitet? Du bekommst dann nämlich für eine Saison mehrere Zeilen aus der Query.
  • Für einen gegebenen Spieler besteht zwischen Saison und Saison_Spieler eine 1:1 Beziehung. Das suggeriert, dass ein Spieler während einer Saison in allen Wettbewerben mit der gleichen Nummer und auf der gleichen Position spielt. Ist das korrekt?
  • Dein Screenshot gibt Spielernummer und -position nicht aus. Das heißt für mich, dass Du die Saison_Spieler-Tabelle gar nicht in der Query brauchst. Wieso hast Du Nr und Pos in der Query drin?

Ich habe Nr und Pos mal dringelassen… Eigentlich muss man nur die Abfrage auf den Wettbewerb entfernen und dafür die Spalte Wettbewerb in die Select-Liste und in die GROUP BY Liste übernehmen. Daraufhin bekommt man eine nach Saison und Wettbewerb gruppierte Liste der Einsätze eines Spielers.

Saisons, an denen er nicht teilgenommen hat, kommen aus diesem GROUP BY Select nicht heraus. Es ist deshalb sinnvoll, mit diesem Teil zu starten und für die gefundenen Saisons die Saison- und Spielerdaten hinzuzumischen.

SELECT Saison.Name, Saison.Jahr, 
       Saison_Spieler.Nr, Saison_Spieler_Pos,
       Stat.Wettbewerb, Stat.Einsaetze, Stat.Eingewechselt, ... Stat.Rot
FROM
       (SELECT Saison_ID as saison_id,
               Wettbewerb as wettbewerb, 
               Spielerstatistik.Spieler_ID as spieler_id,
               COUNT(Spieler_ID) as einsaetze,
               COUNT(eingew) as eingewechselt,
               ...
               COUNT(rot) as rot
        FROM
              Spieltag 
        JOIN 
              Spielerstatistik 
              ON spieltag.ID = spielerstatistik.spieltag_id
        WHERE 
              Spielerstatistik.Spieler_ID = $spieler_id
        GROUP BY
              Saison_ID, Wettbewerb
       ) Stat
       ON Stat.Saison_ID = Saison.ID
JOIN 
       Saison ON Saison.ID = Stat.Saison_ID
JOIN
       Saison_Spieler ON Saison_Spieler.Saison_ID = Stat.Saison_ID
                     AND Saison_Spieler.Spieler_ID = Stat.Spieler_ID
ORDER BY Saison.Jahr, Wettbewerb

Für das Beispiel in deinem Screenshot bekämest Du nun 4 Zeilen heraus, sortiert nach Saisonjahr und Wettbewerb.

Über diese Liste machst Du nun mit PHP eine Gruppenverarbeitung. Es gibt dazu einen Artikel in unserem Wiki, der ist für das, was hier nötig ist, aber zu komplex. Für eine einstufige Gruppenverarbeitung funktioniert es in PHP so:

/* Hier die Query ausführen und Erfolg prüfen */

/* Hier den Seitenkopf schreiben */

$row = $db->fetch();          // Einmal vorauslesen

if ($row == null) {
   /* Hier die Entschuldigung schreiben, dass keine Daten da sind */
}
WHILE ($row) {

   /* Hier <table>,<thead> etc für neue Saison-Tabelle schreiben */

   $saison = $row['saison_id']
   WHILE ($row && $row['saison_id'] == $saison) {

      /* Hier die Zeile für einen Wettbewerb schreiben */

      $row = $db->fetch();   // Nachlesen
   }
   /* Hier </table> etc für letzte Saison-Tabelle schreiben */
}
/* Hier den Seitenfuß schreiben */

Dieser Mustercode verwendet NICHT das bekannte PHP Pattern, im WHILE auch zu lesen (also WHILE ($row = $db->fetch())), statt dessen wird einmal vor der Schleife vorausgelesen, es werden zwei Schleifen geschachtelt (die äußere für die Saisons, die innere für die Saisonzeilen) und es wird am Ende der inneren Schleife nachgelesen. Auf diese Weise erhält man eine Programmstruktur, die der Ausgabedatenstruktur entspricht.

Rolf

--
sumpsi - posui - obstruxi