undso: Verständnisfrage JOIN's

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

  1. 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.

    1. 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.

      1. 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

        1. 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