Hallo Axel,
Das funktioniert soweit in den getesteten Fällen (Kommentare/keine Kommentare, Benutzer vorhanden/Benutzer nicht vorhanden, ...)
Es gibt also wirklich in der Tabelle meldungen Einträge, zu denen es keine Entsprechungen in der Tabelle benutzer gibt? Also Meldungen von nicht vorhandenen Benutzern?
Regulär nicht, es wäre der Ausnahmefall. Wenn jemand eine Meldung verfasst und irgendwann später seinen Konto löschen möchte, wäre es mir lieb, den gesamten Eintrag in der Benutzertabelle löschen zu können, anstatt den Eintrag nur durch einen Flag zu deaktivieren (so eine Spalte habe ich schon, allerdings war sie für andere Fälle gedacht) und ihn dann als Karteileiche zu behalten, die nur dazu da ist, damit bei alten Kommentaren und Meldungen die Namen korrekt angezeigt werden. Ich nehme an, dass das Löschen eines Benutzers, unter dessen Loginnamen vorher großartig Meldungen und Kommentare verfasst wurden, extrem unwahrscheinlich ist. Im Prinzip ist es mir egal, dass bei diesen Meldungen und Kommentaren dann nur noch die Loginnamen angezeigt wird, weil dem Meldungs-Loginnamen keine Zeile mehr in de Benutzertabelle entspricht.
Ich weiß nicht, wie sollte ich das lösen?
Outer-Joins, wie LEFT JOIN und RIGHT JOIN, sind nämlich in jedem Fall langsamer als INNER JOINs.
Ja, das hatte ich gelesen, daher war der Outer Join bewusst gewählt.
Sollte meine Frage also mit Nein zu beantworten sein, wäre folgendes besser:
SELECT
meldungen.msgid,benutzer.vorname,
benutzer.nachname,Count(kommentare.msgid) AS AnzahlKommentare
FROM
(meldungen INNER JOIN benutzer ON meldungen.loginname = benutzer.loginname)
LEFT JOIN kommentare ON meldungen.msgid = kommentare.msgid
GROUP BY meldungen.msgid, benutzer.vorname, benutzer.nachname;
Ist die Klammerung des ersten Joins im Allgemeinen wichtig bzw. ratsam?
Die vielen Felder nach GROUP BY sind so nach SQL vorgeschrieben. Demnach muss in gruppierten Abfragen jedes Feld entweder zur Grupperung gehören oder Teil einer Aggregatfunktion sein.
Also sollte ich, wenn ich die Spalten
meldungen.msgid, DATE_FORMAT(meldungen.time, "%d.%m.%Y, %H:%i Uhr") AS time, DATE_FORMAT(meldungen.aenderung, "%d.%m.%Y, %H:%i Uhr") AS aenderung, meldungen.zugriff, meldungen.loginname, meldungen.meldungstitel, meldungen.meldungstext,
benutzer.vorname, benutzer.nachname,
COUNT(kommentare.msgid) AS kommentarzahl
selecte, sie unter GROUP BY entsprechend aufführen bis auf die kommentarzahl?
GROUP BY meldungen.msgid, time, aenderung, meldungen.zugriff, meldungen.loginname, meldungen.meldungstitel, meldungen.meldungstext, benutzer.vorname, benutzer.nachname
Es ginge also auch so:
[...]
Wobei ich jetzt nicht weiß, ob MySQL die Aggregatfunktion First() kennt.
Offenbar nicht...
MySQL akzeptiert die Abfrage auch so, wie Du sie gruppiert hast, nimmt aber auch ohne explizite Aggregatfunktion jeweils den ersten Wert der Felder, nach denen nicht gruppiert wird.
Was hat es mit dieser Gruppierung auf sich? Mir scheint die Gruppierung nach meldungen.msgid ausreichend, wenn ich mir das Joinen veranschauliche.
Wenn meine Frage mit Ja zu beantworten ist, geht es natürlich nur so, wie Du es bereits machst. Dann vergiss aber nicht Indexe auf die Felder zu setzen, die zu den JOIN-Verknüpfungen gehören und nach denen gruppiert und sortiert wird.
Aha, das hatte ich vermutet.
Mathias