dedlfix: Query gesucht

Beitrag lesen

Tach!

ich habe inzwischen die (nein besser: eine) Query erstellt, die mir aber das Ergebnis nicht zeigt, was ich erwarte.

SELECT Name FROM spieler
LEFT JOIN m_n_tabelle ON spieler.SID = m_n_tabelle.SID
WHERE
( (SELECT COUNT(*) FROM spiele) = (SELECT spieler_id COUNT(*) FROM m_n_tabelle GROUP BY spieler_id) )

Nehmen wir erstmal das WHERE:

( (SELECT COUNT(*) FROM spiele) = (SELECT spieler_id COUNT(*) FROM m_n_tabelle GROUP BY spieler_id) )

Links gibt es genau ein Ergebnis, rechts gibt es je eines Pro Spieler, also eine Ergebnismenge > 1 (wenn man sich mal das spieler_id vor dem COUNT(*) wegdenkt). Eins mit mehreren zu vergleichen ist nicht besonders sinnvoll. Sollte das nicht auch zu einem Fehler führen?

Punkt zwei ist, dass du keine Verbindung zwischen den Subquerys im WHERE und dem Rest hast. Die linke braucht keine, aber die rechte soll zu jedem einzelnen Spieler aus der Haupt-Query die Anzahl liefern. Also brauchst du da kein GROUP BY sondern ein WHERE spieler_id gleich der id vom Spieler der Hauptquery ist.

Der Left Join ist auch nicht notwendig, wenn du mit correlated Subquery arbeitest (vorausgesetzt, du macht die Korrelation noch rein). Wenn du mit dem Join arbeiten willst, dann braucht es das GROUP BY aber direkt und nicht in einer Subquery. Ungeachtet davon brauchst du das COUNT(*) FROM Spiele weiterhin als Subquery. Und da es mit dem gruppierten COUNT der Spiele pro Spieler zusammenarbeiten soll, kann es nicht im WHERE stehen (das vor dem GROUP BY ausgewertet wird), sondern muss "weiter nach hinten" ins HAVING.

Da wäre also die eine Lösungsmöglichkeit:

SELECT Name FROM spieler s
WHERE (SELECT COUNT(*) FROM spiele) = (SELECT COUNT(*) FROM m_n_tabelle m WHERE s.SID = m.spieler_id)

Die beiden Aliasse können auch wegfallen, wenn die Spaltennamen eindeutig sind. (Du bist bei der Benennung in deinem Beispiel-Code nicht konsequent gewesen. Beim Join ist es SID, in der Subquery spieler_id.)

Und nun noch die zweite:

SELECT spieler.SID, COUNT(*) anzahl FROM spieler
LEFT JOIN m_n_tabelle ON spieler.SID = m_n_tabelle.SID
-- bei Bedarf noch WHERE auf irgendwelche anderen Bedingungen
GROUP BY spieler.SID
HAVING (SELECT COUNT(*) FROM spiele) = anzahl

Andere DBMSe erlauben in der SELECT-Klausel neben dem COUNT nur das spieler.SID, nach dem auch gruppiert wurde. MySQL erlaubt hingegen auch die Angabe weiterer Felder. Du wolltest ja eigentlich noch andere Spielerdaten, zum Beispiel den Namen haben. In diesem Fall ist der Name und alle anderen Spielerdaten durch die Gruppierung auf Spieler-ID eindeutig und kann unter MySQL problemlos ins SELECT geschrieben werden. Wenn durch eine Gruppierungsbedingung unterschiedliche Daten in eine Gruppe gelangen können, so ergibt ein Selektieren darauf einen zufälligen Wert aus der Anzahl der möglichen. Hier wäre das der Fall, wenn du von der m_n_tabelle ein Feld selektieren würdest. Da gibts zwar vermutlich nur noch die Spiel-ID, aber das sind pro Gruppe ja mehrere unterschiedliche Werte, und das würde dann nicht eindeutig enden. Abgesehen davon brauchst du ja die Spiel-ID nicht im Ergebnis. Also stellt das hier kein Problem dar.

dedlfix.