Hallo,
ich bin derzeit an der Erstellung einer Internetseite für unsere wöchentliches Bundesliga-Tippspiel um mich auch mal in PHP und SQL wieder reinzufuchsen...
Nun bin ich aber auf ein kleines problem gestoßen und bräuchte eure hilfe bei einem SQL-Statement, ob dies mit einem RIGHT/LEFT join möglich ist.
ja, das ist mit einem LEFT JOIN möglich, mit einem RIGHT JOIN selbstverständlich auch ;-)
Ich habe 3 Tabellen mit folgenden Strukturen:
- Users (für die Spieler)
+UserID(int, Primary Key)
+UserName(varchar)
+aktiv(aktiv) -> dient für spätere Historie um auch Saisonübergreifend Tipps von Spielern beizubehalten
- spieltag (für die Speicherung der wirklichen Partien und deren Ergebnisse)
+ID (int, Primary Key)
+Heim (int, Fremdschlüssel zur TeamID einer anderen Tabelle)
+Gast (int, Fremdschlüssel zur TeamID einer anderen Tabelle)
+ToreHeim (int)
+ToreGast (int)
+spieltag (int)
- spieltagtippen (Hier sind die tipps der Spieler)
- IDSpieler(int, Primary Key)
- IDSpiel(int, Primary Key)
- TippToreHeim (int)
- TippToreGast (int)
- spieltag (int)
die Spalte Spieltag in der Tipp-Tabelle erscheint mir überflüssig.
Ziel ist es, dass ich Alle Spiele eines Spieltages mit sämtlichen Tipps mir darstellen lasse, auch von denen, die nicht getippt haben (deise sind auch nicht in der tabelle spieltagtippen enthalten)!
Mit dem SQL-Statement:
SELECT ID, Heim, Gast, ToreHeim, ToreGast, UserID, UserName
FROM
spieltag
CROSS JOIN users
WHERE aktiv = true
AND spieltag =1
ORDER BY UserID ASC , ID ASC
> Vielen Dank für die Grafik, ich hoffe sie hilft mir weiter...wenigstens mal schön übersichtlich dargestellt denke mal selber ein bisserl malen könnte helfen
> [Update]
> Mit einem Cross Join bekomme ich es hin, dass jeder aktive User auch mit allen Spielen eines Spieltages verbunden wird:
Vielen Dank, wenn Du Cross-Postings vermiedest oder wenigstens auch die Grafik verlinktest.
> nun muss ich noch das ganze mit der dritten tabelle, den Tipps verbinden die dann eben zusätzlich dort eingebunden werden...
> Egal wie ich die daten kombiniere, ich bekomme es nicht hin, dass für das spiel 38 von Spieler 2 auch ein datensatz (Nämlich NULL bei den Tipps) ausgegeben wird!
Du hast es doch schon weit gebracht:
Du hast die Kombination aller Mitspieler und Partien an einem bestimmten Spieltag. Diese Datensätze möchtest Du alle haben, dazu die abgegebenen Tipps, wenn vorhanden. Das ist eine typische Aufgabe für einen [OUTER JOIN](http://aktuell.de.selfhtml.org/artikel/datenbanken/joins/#leftright_join).
Du hast mindestens zwei Möglichkeiten, Dein Ergebnis zu bekommen:
a) über einen [Mehrfachjoin](http://aktuell.de.selfhtml.org/artikel/datenbanken/fortgeschrittene-joins/mehrfachjoin1.htm),
b) mit einem Subselect.
Schauen wir uns a) an: den Mehrfachjoin.
Die Ausgangstabelle wird durch Deinen Cross-Join erzeugt. Damit wir einfach weiterjoinen können, schreibst Du Deine WHERE-Klausel in die Join-Bedingung um:
~~~sql
SELECT
ID,
Heim,
Gast,
ToreHeim,
ToreGast,
UserID,
UserName
FROM
spieltag
CROSS JOIN
users
ON
aktiv = true AND spieltag = 1
sollte abgesehen von der Sortierung das gleiche Ergebnis liefern. Du sortierst eh' das Endergebnis, nicht zwischendurch.
Erweitere das Statement um den LEFT JOIN auf die Tipptabelle und verwende Tabellen-Aliasnamen um das lästige Ausschreiben der Tabellennamen etwas angenehmer zu gestalten:
SELECT
st.ID,
st.Heim,
st.Gast,
st.ToreHeim,
st.ToreGast,
u.UserID,
u.UserName,
t.TippToreHeim,
t.TippToreGast
FROM (
spieltag st
JOIN -- auf CROSS kann man verzichten
-- dann verstehen's mehr SQL-Dialekte
users u
ON
aktiv = true AND spieltag = 1)
LEFT JOIN
spieltagtippen t
ON
u.UserID = t.IDSpieler
AND
st.ID = t.IDSpiel
~~~ [1]
MySQL sollte schon in der Version 5.0.12 oder neuer vorliegen. Ältere MySQL-Dialekte liefern bei komplizierteren Joins gerne systematisch falsche Ergebnisse aus und ignorierten vor Version 5.0.1 Klammern, siehe [Handbuch](http://dev.mysql.com/doc/refman/5.0/en/join.html).
Freundliche Grüße
Vinzenz
[1] Statement getestet mit MS SQL Server 2005 Express Edition.