Johannes Völlinger: Problem bei LEFT OUTER JOIN

Hi!

Da ich nicht aus diesem MYSQL Ergebnis schlau werde, werfe ich diese Frage mal in die Runde.
Bastel gerade ein News Skript mit zwei Tabellen: News und Kommentare. Ich will die Anzahl der Kommentare zu jedem Newsbeitrag anzeigen lassen und nutze einen LEFT OUTER JOIN in Verbindung mit GROUP BY und Count, um dies zu realisieren. Klappt mit drei Testdaten auch so wie erwartet und er gibt die Anzahl richtig aus (3,0,1). Das Problem kommt aber, sobald es mehrere News OHNE Kommentare gibt. Er zeigt mir partu nur EINEN Datensatz an, zu dem es keine Kommentare gibt, alle anderen Nachrichten (ohne Kommentare) werden nicht ins Ergebnis aufgenommen. Woran liegt das und wie kann ich das beheben?

cya
Johannes

  1. Hi,

    wie sieht Deine Query aus? Zeig mal! Hört sich nach falschem Parameter für die GROUP-BY-Klausel an...

    HTH Robert

    1. Hi,

      wie sieht Deine Query aus? Zeig mal! Hört sich nach falschem Parameter für die GROUP-BY-Klausel an...

      Also an der Group by Klausel kann nicht liegen, dafür kommt nur das Feld in Frage. Kann auch keinen Logikfehler entdecken, er macht ja auch sonst alles richtig, nur das er mir nicht mehr als einen Datensatz anzeigen will, zu dem es in der "rechten" Tabelle Kommentare keine Datensätze gibt.
      Hier der Query:

      SELECT news.NEWS_ID, news.Topic, news.Nachricht, news.Verfasser, news.Quelle, news.Datum, count(comment.KOMM_ID) FROM News as news LEFT OUTER JOIN Kommentare AS comment ON news.NEWS_ID=comment.NEWS_ID GROUP BY comment.NEWS_ID ORDER BY news.Datum

      Auch mit dem Zusatz "WHERE comment.KOMM_ID IS NULL" gibt er nur einen Datensatz aus, der keinen Kommentar hat (5 müßten es sein)!

      Auch das weglassen des "OUTER" aus dem LEFT OUTER JOIN, bringt nichts.

      1. Hallo,

        SELECT news.NEWS_ID, news.Topic, news.Nachricht, news.Verfasser, news.Quelle, news.Datum, count(comment.KOMM_ID) FROM News as news LEFT OUTER JOIN Kommentare AS comment ON news.NEWS_ID=comment.NEWS_ID GROUP BY comment.NEWS_ID ORDER BY news.Datum

        Zählt MySQL NULL-Werte? Probiere mal:

        SELECT news.NEWS_ID, news.Topic, news.Nachricht, news.Verfasser, news.Quelle, news.Datum, count(IFNULL(comment.KOMM_ID,1)) FROM News as news LEFT OUTER JOIN Kommentare AS comment ON news.NEWS_ID=comment.NEWS_ID GROUP BY comment.NEWS_ID ORDER BY news.Datum

        viele Grüße

        Axel

        1. Zählt MySQL NULL-Werte? Probiere mal:

          SELECT news.NEWS_ID, news.Topic, news.Nachricht, news.Verfasser, news.Quelle, news.Datum, count(IFNULL(comment.KOMM_ID,1)) FROM News as news LEFT OUTER JOIN Kommentare AS comment ON news.NEWS_ID=comment.NEWS_ID GROUP BY comment.NEWS_ID ORDER BY news.Datum

          Hmhm, ein interessanter Ansatz, das hatte ich noch nicht ausgetestet. Leider kommt auch hier wieder dasselbe Ergebnis wie bei meinem vorherigen LEFT OUTER JOIN auch. Langsam glaube ich, der Fehler liegt nicht im Query ... *weiter grübelt*

          cya
          Jubbi

          1. Hallo,

            dann kann man eigentlich nur versuchen, den Fehler einzugrenzen:

            MySQL erlaubt eine vom Standard abweichende Group By Syntax, in der nicht alle ausgewählten Felder mit in die Gruppe oder Aggregatfunkionen aufgenommen werden. So richtig getraut habe ich dem aber noch nie. Machen wir's mal ANSI-standardkonform

            SELECT comment.NEWS_ID, count(IFNULL(comment.KOMM_ID,1)) as cnt FROM News as news LEFT OUTER JOIN Kommentare AS comment ON news.NEWS_ID=comment.NEWS_ID GROUP BY IFNULL(comment.NEWS_ID,1) ORDER BY news.Datum

            richtige Anzahl? Dann:

            SELECT max(news.NEWS_ID), max(news.Topic), max(news.Nachricht), max(news.Verfasser), max(news.Quelle), max(news.Datum), count(IFNULL(comment.KOMM_ID,1)) FROM News as news LEFT OUTER JOIN Kommentare AS comment ON news.NEWS_ID=comment.NEWS_ID GROUP BY IFNULL(comment.NEWS_ID,1) ORDER BY news.Datum

            viele Grüße

            Axel

      2. Hi,

        SELECT news.NEWS_ID, news.Topic, news.Nachricht, news.Verfasser, news.Quelle, news.Datum, count(comment.KOMM_ID)
            FROM News as news
            LEFT OUTER JOIN Kommentare AS comment ON news.NEWS_ID=comment.NEWS_ID
            GROUP BY comment.NEWS_ID
            ORDER BY news.Datum

        Das left-outer-join-Gedöns verwirrt mich immer; könnte ein Problem darin liegen, daß Du nach dem der Spalte NEWS_ID aus der rechten Tabelle gruppierst? Warum überhaupt? Wie wäre es, den Join über eine WHERE-Bedingung auszuführen (und in den Klauseln GROUP und ORDER nur die Ergebnisspalten zu benennen):

        SELECT news.NEWS_ID, news.Topic, news.Nachricht, news.Verfasser, news.Quelle, news.Datum, count(comment.KOMM_ID)
            FROM News as news, Kommentare as comment
            WHERE news.NEWS_ID = comment.NEWS_ID
            GROUP BY NEWS_ID
            ORDER BY Datum

        ?

        HTH Robert

        1. Das left-outer-join-Gedöns verwirrt mich immer; könnte ein Problem darin liegen, daß Du nach dem der Spalte NEWS_ID aus der rechten Tabelle gruppierst? Warum überhaupt? Wie wäre es, den Join über eine WHERE-Bedingung auszuführen (und in den Klauseln GROUP und ORDER nur die Ergebnisspalten zu benennen):

          Mit dem "normalen" OUTER JOIN kommst du zwar an die Ergebnisse ran die sich in der News UND der Kommentar Tabelle befinden, allerdings brauche ich auch die Datensätze in meinem Result, die keinen Datensatz in der "benachbarten" (rechten) Tabelle haben (sprich: kein Kommentar zur News). Das ist ja auch der eigentlich Sinn des LEFT und RIGHT OUTER JOINS, mal abgesehen von der Tatsache, daß sie schneller ausgeführt werden (kartesisches Produkt).

          Mit nem normalen Wald und Wiesen Join bräuchte ich schon zwei einzelne Abfragen, um an das gewünschte Ergebnis zu kommen und das möchte ich auf jeden Fall vermeiden.

          cya
          Johannes

          1. Hi,

            Mit dem "normalen" OUTER JOIN kommst du zwar an die Ergebnisse ran die sich in der News UND der Kommentar Tabelle befinden, allerdings brauche ich auch die Datensätze in meinem Result, die keinen Datensatz in der "benachbarten" (rechten) Tabelle haben (sprich: kein Kommentar zur News).

            Ja klar, ich sollte besser nachdenken, bevor ich antworte. Was war mit dem anderen Hinweis, den Tabellen-Alias aus der GROUP-BY-Klausel zu nehmen: GROUP BY NEWS_ID statt GROUP BY comment.NEWS_ID? Das scheint mir problematisch...

            HTH Robert

            1. Was war mit dem anderen Hinweis, den Tabellen-Alias aus der GROUP-BY-Klausel zu nehmen: GROUP BY NEWS_ID statt GROUP BY comment.NEWS_ID? Das scheint mir problematisch...

              Nene, den Alias brauchste, sonst spuckt dir MYSQL nen Fehler aus (zweideutig). Ich verwende den Schlüssel NEWS_ID ja sowohl in der Tabelle News (Primary Key), als auch in der Tabelle Kommentar (Foreign Key). Deshalb braucht die Datenbank auch ne eindeutige Zuordnung über den Alias Namen. Keine Ahnung, warum er immer nur einen der 5 News mit NULL-Wert (ohne Kommentar) anzeigen will und nicht alle. >_<

              cya
              Johannes

              1. Hi,

                Nene, den Alias brauchste, sonst spuckt dir MYSQL nen Fehler aus (zweideutig). Ich verwende den Schlüssel NEWS_ID ja sowohl in der Tabelle News (Primary Key), als auch in der Tabelle Kommentar (Foreign Key). Deshalb braucht die Datenbank auch ne eindeutige Zuordnung über den Alias Namen. Keine Ahnung, warum er immer nur einen der 5 News mit NULL-Wert (ohne Kommentar) anzeigen will und nicht alle. >_<

                mir fehlt der Glaube... GROUP BY und ORDER BY orientieren sich an den Spalten des Result sets (ich habe in keinem SQL-Dialekt jemals dort Tabellen-Aliase verwendet gesehen), dort gibt es keine Zweideutigkeit. Hättest die bei NEWS_ID-Spalten im Ergebnis, so müßte mindestens eine einen Alias erhalten, um keine Fehler zu werfen.

                Hast Du es einmal ohne Alias in GROUP BY versucht? Oder vielleicht den Spaltenindex (GROUP BY 1), wenn Dir das lieber ist? Das würde mich überzeugen...

                HTH Robert

                1. Hast Du es einmal ohne Alias in GROUP BY versucht? Oder vielleicht den Spaltenindex (GROUP BY 1), wenn Dir das lieber ist? Das würde mich überzeugen...

                  Da ich eh keine Ideen mehr habe, ziehe ich gerne jede Möglichkeit in Betracht. ^^

                  *umspechtet*
                  *Abfrage abschickt*
                  *blöd guckt*

                  Ich weiß nicht, ob ich mich jetzt freuen oder schreien soll. *sich fürs schreien entscheidet* ^^
                  Es kommt jetzt genau das Ergebnis raus, das ich erwartet, aber vorher nicht bekommen habe! >_< Ich habe sowohl in SQL als auch in MySQL immer den Alias Namen verwendet und nie Probleme gehabt. Selbst in meinen Onlinedokumentationen und Büchern verwenden sie in ihren GROUP BY Beispielen den Alias in Verbindung mit dem Feld-Namen. Wieso zum Kuckuck spinnt aber MySQL so rum??? Er hat mir vorher auch die richtige Anzahl an Datensätzen ausgespuckt, nur wollte er partu nicht mehr als einen anzeigen. >_<
                  Egal, was solls. -_-' Es läuft jetzt und das ist alles was ich wollte. Danke dir für den Tip, auch wenn ich jetzt mit nem großen Fragezeichen weiter am Newsskript basteln werde. :-)

                  cya
                  Johannes

                  1. Hi,

                    *sich fürs schreien entscheidet* ^^

                    schön.

                    Ich habe sowohl in SQL als auch in MySQL immer den Alias Namen verwendet und nie Probleme gehabt. Selbst in meinen Onlinedokumentationen und Büchern verwenden sie in ihren GROUP BY Beispielen den Alias in Verbindung mit dem Feld-Namen. Wieso zum Kuckuck spinnt aber MySQL so rum???

                    Ich habe GROUP BY immer als auf Ergebnisspalten angewendet angesehen, welche keinen Bezug mehr zu ihren Ursprungstabelle haben. Deshalb betrachte ich den Alias in der Klausel auch als Fremdkörper. Gegenüber ANSI hat bietet MySQL allerdings die Möglichkeit, GROUP BY auch auf nicht im Result set enthaltene Spalten anzuwenden, dann wird gegebenenfalls der Tabellen-Alias erforderlich.

                    HTH Robert

  2. versuchs mal ohne das OUTER...einfach nur n Left Join