Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Letzten Kommentar anzeigen, der nur 1 Kommentar pro Benutzer enthält

Warum es mit GROUP BY nicht funktioniert

SELECT * kann nicht mit GROUP BY verwendet werden; es ist ungültiges SQL. GROUP BY wählt keine Tabellenzeilen aus. Es erstellt Gruppen von Zeilen unter Verwendung der bereitgestellten Ausdrücke, generiert dann aus jeder Gruppe einen neuen Datensatz und berechnet jede Spalte dieses neuen Datensatzes unter Verwendung der im Ausdruck enthaltenen Werte.

Die Spalten, die in SELECT erscheinen -Klausel muss eine der folgenden Regeln erfüllen:

  • erscheinen auch im GROUP BY Klausel;
  • werden mit GROUP BY Aggregatfunktionen ;
  • sind funktional abhängig von den Spalten, die in GROUP BY erscheinen Klausel.

Während * ist eine Abkürzung für alle Spaltennamen der von der Abfrage verwendeten Tabelle(n), für Ihre Abfrage nur der user Spalte eine der oben genannten Anforderungen erfüllen.

Vor Version 5.7.5 MySQL hat die dritte obige Regel nicht implementiert. Früher akzeptierte es Abfragen, die im SELECT enthalten waren Klauselspalten, die keinem der GROUP BY folgen Bedarf. Der von der Abfrage für solche Spalten zurückgegebene Wert war unbestimmt .

Seit Version 5.7.5 lehnt MySQL das GROUP BY ab Abfragen, die die Anforderungen erfüllen.

Die Lösung

Wie auch immer, die Lösung für Ihr Problem beinhaltet nicht GROUP BY . Dies kann leicht mit einem LEFT JOIN erreicht werden mit den richtigen Bedingungen:

SELECT lc.*
FROM comments lc               # 'lc' from 'last comment'
    LEFT JOIN comments nc      # 'nc' from 'newer comment'
        ON lc.user = nc.user   # both comments belong to the same user
        AND lc.id < nc.id      # 'nc' is newer than 'lc'
WHERE nc.id IS NULL            # there is no 'newer comment'
ORDER BY lc.id DESC
LIMIT 10

Wie es funktioniert

Es schließt sich der Tabelle comments an , mit dem Alias ​​lc ("lc" aus dem "letzten Kommentar" eines Benutzers) gegen sich selbst, aliasiert als nc ("nc" von "neuerer Kommentar"). Die Join-Klausel passt zu jedem Eintrag von lc mit allen Einträgen von nc die demselben Benutzer gehören (lc.user = nc.user ) und sind neuer (lc.id < nc.id; Ich bin davon ausgegangen, dass die IDs nacheinander zugewiesen werden und neuere Kommentare größere Werte für id haben ).

Die Verwendung von LEFT JOIN stellt sicher, dass jede Zeile von lc erscheint im Ergebnis des Joins, selbst wenn keine übereinstimmende Zeile in nc gefunden wird (weil es keinen neueren Kommentar desselben Benutzers gibt). In diesem Fall NULL wird anstelle der Felder von nc verwendet . Das WHERE -Klausel behält in der endgültigen Ergebnismenge nur die Zeilen mit NULL in nc.id; das heißt im lc teilweise enthalten sie den neuesten Kommentar jedes Benutzers.

Die SELECT -Klausel enthält alle Felder von lc (die von nc sind alle NULL , ohnehin). Der ORDER BY -Klausel kann verwendet werden, um die Ergebnismenge zu sortieren. ORDER BY lc.id DESC setzt die neuesten Kommentare zuerst und das LIMIT -Klausel hält die Ergebnismenge auf einer anständigen Größe.