Verständnisfrage JOIN's
undso
- datenbank
0 Struppi0 undso0 Vinzenz Mai0 undso
Hi Forum,
ich komme zwar mit leichten Joins zurecht, bei mir hakt es aber, wenn keine Beziehungen zwischen mehreren Tabellen da sind.
Tabelle News
NewsID Thema Hits Kommentare Kategorie
1 Liebe und Partnerschaft 10 1 2
2 EU Krise 5 0 2
(JA ich könnte eventuell die Spalte Kommentare sparen)
Tabelle Kommentare
ID NewsID UserID Kommentar
1 1 1234 Ich halte nichts von Liebe
Tabelle User
UserID Name Geschlecht
1234 Heinz Weiblich
Was kein Problem nun kein Problem ist, wenn zwischen Thema und Kommentare eine Verbindung da ist.
SELECT A.Thema, A.Hits, A.Kommentare, B.Kommentar FROM News AS A INNER JOIN Kommentare AS B on A.NewsID=B.NewsID where A.Kategorie=2;
Jetzt holt er schön die erste News (Liebe und Partnerschaft), da die Verbindung A.NewsID=B.NewsID ja besteht. Die Frage ist, ob er die zweite News (EU Krise) holt, weil dazu ja kein Kommentar besteht und somit A.NewsID=B.NewsID nicht zutrifft.
Bzw. wenn ich auf eine Dritte Tabelle zugreife und eine Beschränkung für die dritte Tabelle einfüge, sollte er dennoch den zweiten News holen:
SELECT A.Thema, A.Hits, A.Kommentare, B.Kommentar FROM News AS A INNER JOIN Kommentare AS B on A.NewsID=B.NewsID INNER JOIN User AS C on B.UserID=C.userID where A.Kategorie=2 AND C.Geschlecht="Weiblich";
Ich hoffe, ich finde auch eine Lektüre, wo die Unterschiede zwischen INNER JOIN, LEFT JOIN, OUTER JOIN usw. verständlich erklärt werden.
Es gibt auch manche Programmierer, die die Tabellen einfach mit Komma getrennt hinten auflisten:
SELECT A.Thema, A.Hits, A.Kommentare, B.Kommentar FROM News AS A, Kommentare AS B on A.NewsID=B.NewsID where A.Kategorie=2;
Grüße
Ich hoffe, ich finde auch eine Lektüre, wo die Unterschiede zwischen INNER JOIN, LEFT JOIN, OUTER JOIN usw. verständlich erklärt werden.
http://aktuell.de.selfhtml.org/artikel/datenbanken/joins/index.htm
http://aktuell.de.selfhtml.org/artikel/datenbanken/fortgeschrittene-joins/index.htm
Struppi.
Hi noch einmal, habe mir die erste Seite komplett durchgelesen,die Joins sind mir jetzt einwenig klarer.
Hab zu Testzwecken drei Tabellen angelegt:
CREATE TABLE test\_news
(
newsid
int(11) NOT NULL auto_increment,
thema
varchar(250) default '',
hits
int(11) default 0,
kommentare
int(11) default 0,
kategorie
int(11) default 0,
PRIMARY KEY (newsid),
INDEX (newsid)
) ;
CREATE TABLE test\_newscomments
(
commentid
int(11) NOT NULL auto_increment,
newsid
int(11) default 0,
userid
int(11) default 0,
kommentar
varchar(250) default '',
PRIMARY KEY (commentid),
INDEX (newsid)
) ;
CREATE TABLE test\_user
(
userid
int(11) default 0,
username
varchar(250) default '',
geschlecht
int(11) default 0,
PRIMARY KEY (userid),
INDEX (userid)
) ;
###############################################################################
Zwei Nachrichten in die Newstabelle
INSERT INTO test\_news
( newsid
, thema
, hits
, kommentare
, kategorie
) VALUES ('', 'EU Krise', '10', '2', '3');
INSERT INTO test\_news
( newsid
, thema
, hits
, kommentare
, kategorie
) VALUES ('', 'Liebe', '5', '0', '3');
Zwei Kommentare nur für die erste News
INSERT INTO test\_newscomments
( commentid
, newsid
, userid
, kommentar
) VALUES ('', '1', '12345', 'Das ist Schade');
INSERT INTO test\_newscomments
( commentid
, newsid
, userid
, kommentar
) VALUES ('', '1', '67890', 'Wird schon wieder');
Zwei USer in der Usertabelle
INSERT INTO test\_user
( userid
, username
, geschlecht
) VALUES ('12345', 'Lisa', '1');
INSERT INTO test\_user
( userid
, username
, geschlecht
) VALUES ('67890', 'Udo', '2');
Folgende Joins sind mir klar. Er führt beide Tabellen zusammen, falls das Kriterium "A.newsid=B.newsid" passt. Es wird die erste News 2 Mal aufgelistet, da 2 Kommentare.
SELECT A.thema, A.hits, A.kommentare, b.kommentar, b.userid FROM test_news AS A INNER JOIN test_newscomments AS B on A.newsid=B.newsid;
Left Join. Er listet auf alle Fälle die Datensätze von der Linken Tabelle auf, falls das Kriterium "A.newsid=B.newsid" passt, fügt er noch die Kommentare dazu, ansonsten werden diese Felder mit NULL aufgefüllt. Es wird die erste News 2 Mal aufgelistet, da zwei Kommentare und einmal die zweite News mit NULL-Felder, da keine Kommentare
SELECT A.thema, A.hits, A.kommentare, b.kommentar, b.userid FROM test_news AS A LEFT JOIN test_newscomments AS B on A.newsid=B.newsid;
Wenn ich nun drei Tabellen verbinde, hakt es bei mir. Liste alle News von test_news auf. Falls Kommentare vorhanden hole noch die Kommentare mit Userangaben. Hier listet er nur die ersten Beiden News auf.
SELECT A.thema, A.hits, A.kommentare, b.kommentar, b.userid, C.username FROM test_news AS A LEFT JOIN test_newscomments AS B on A.newsid=B.newsid INNER JOIN test_user AS C on B.userid=C.userid;
Er sollte jedoch die zweite News ohne Kommentare auch auflisten.
Hallo
Hi noch einmal, habe mir die erste Seite komplett durchgelesen,die Joins sind mir jetzt einwenig klarer.
und warum noch nicht den Artikel, der sich mit Mehrfachjoins befaßt?
CREATE TABLE
test\_news
(
newsid
int(11) NOT NULL auto_increment,
) ;
[...]
Die schreckliche Backtickitis läßt auf MySQL schließen. Welche Version.
MySQL geht erst ab Version 5.0.12 einigermaßen vernünftig mit komplexeren Joins um. Vorher gibt's gern auch mal völlig falsche Resultate :-)
Wenn ich nun drei Tabellen verbinde, hakt es bei mir. Liste alle News von test_news auf. Falls Kommentare vorhanden hole noch die Kommentare mit Userangaben. Hier listet er nur die ersten Beiden News auf.
SELECT A.thema, A.hits, A.kommentare, b.kommentar, b.userid, C.username FROM test_news AS A LEFT JOIN test_newscomments AS B on A.newsid=B.newsid INNER JOIN test_user AS C on B.userid=C.userid;
Du möchtest also alle Beiträge und falls es noch Kommentare gibt, die entsprechenden Informationen aus der Kommentar- und Benutzertabelle?
SELECT
news.thema, -- Aliasnamen bitte *sinnvoll* wählen
news.hits, -- A, B oder C sind keine sinnvollen Namen!
news.kommentare,
comments.kommentar,
comments.userid,
user.username
FROM
test_news news -- ich persönlich verzichte bei Aliasnamen für
-- Tabellen auf das Schlüsselwort AS, weil das
-- nicht jedes DBMS versteht :-)
LEFT JOIN (
test_newscomments comments
INNER JOIN
test_user user
ON
comments.userid = user.userid
)
ON
news.newsid = comments.newsid
Beachte, dass MySQL < 5.0.x Klammern ignoriert.
Beachte, dass MySQL < 5.0.12 ein falsches Ergebnis liefert.
Bei Datenbankfragen, insbesondere bei MySQL, ist es sehr wichtig, das verwendete DBMS *und* die verwendete Version anzugeben.
Freundliche Grüße
Vinzenz
Hi vinzenz,
und warum noch nicht den Artikel, der sich mit Mehrfachjoins befaßt?
werde ich gleich nachholen und es mir anschauen.
Die schreckliche Backtickitis läßt auf MySQL schließen. Welche Version.
MySQL geht erst ab Version 5.0.12 einigermaßen vernünftig mit komplexeren Joins um. Vorher gibt's gern auch mal völlig falsche Resultate :-)
Lokal habe ich mySQL 5.0.15 und auf dem Server müsste es die 5.0.12 sein, wenn ich mich nicht täusche.
Du möchtest also alle Beiträge und falls es noch Kommentare gibt, die entsprechenden Informationen aus der Kommentar- und Benutzertabelle?
Genau, und mit Deiner Query klappt es auch optimal.
SELECT
news.thema, -- Aliasnamen bitte sinnvoll wählen
news.hits, -- A, B oder C sind keine sinnvollen Namen!
news.kommentare,
comments.kommentar,
comments.userid,
user.username
FROM
test_news news -- ich persönlich verzichte bei Aliasnamen für
-- Tabellen auf das Schlüsselwort AS, weil das
-- nicht jedes DBMS versteht :-)
LEFT JOIN (
test_newscomments comments
INNER JOIN
test_user user
ON
comments.userid = user.userid
)
ON
news.newsid = comments.newsid
>
> Beachte, dass MySQL < 5.0.x Klammern ignoriert.
> Beachte, dass MySQL < 5.0.12 ein falsches Ergebnis liefert.
>
Die Query ist auch recht einleuchtend für mich nun. Hole die oben aufgezählten Spalten von test\_news news (das zweite news ist dann wohl ein Alias, wobei ich das mit A, B und C etwas anschaulicher finde, ist aber mehr eine Geschmackfrage).
Alle Datensätze von test\_news werden ausgespuckt da LEFT JOIN. Und der rechte Teil wird nur befüllt, falls das Kriterium comments.userid = user.userid zutrifft.
Ob ich die anzahl der Kommentare in test\_news noch separat anlege, muss ich mir noch überlegen. Wahrscheinlich lösche ich es und berechne es immer mit Anhang von count(\*) damit es dann normalisiert ist.
Eine andere Frage, wenn ich dich schon an der Hotline habe. Ich hatte vor ein paar Tagen einen Thread gestartet, aber leider keine Antwort erhalten, ist mittlerweile auch schon im Archiv. http://forum.de.selfhtml.org/archiv/2008/2/t166515/#m1085967
Konnte ich mein Problem dort überhaupt verständlich erklären?
Hättest mir da nen kleinen Tipp?
Grüße