Ich habe die folgende Tabelle mit Fragen:
ID | asker
1 | Bob
2 | Bob
3 | Marley
Ich möchte jeden Fragenden nur einmal auswählen. Wenn mehrere Fragesteller mit demselben Namen vorhanden sind, wählen Sie die höchste ID aus. Also die erwarteten Ergebnisse:
ID | asker
3 | Marley
2 | Bob
Ich verwende die folgende Abfrage:
SELECT * FROM questions GROUP by questions.asker ORDER by questions.id DESC
Ich erhalte folgendes Ergebnis:
ID | asker
3 | Marley
1 | Bob
Also wählt es den ersten "Bob" aus, den es trifft, anstatt den letzten.
Vielen Dank
Wenn Sie die letzte id
für jede asker
wünschen, sollten Sie eine Aggregatfunktion verwenden:
SELECT max(id) as id,
asker
FROM questions
GROUP by asker
ORDER by id DESC
Der Grund für das ungewöhnliche Ergebnis ist, dass MySQL eine Erweiterung von GROUP BY
verwendet, wodurch Elemente in einer Auswahlliste nicht aggregiert werden können und nicht in der GROUP BY-Klausel enthalten sind. Dies kann jedoch zu unerwarteten Ergebnissen führen, da MySQL die zurückgegebenen Werte auswählen kann. (Siehe MySQL-Erweiterungen für GROUP BY )
Aus den MySQL-Dokumenten:
MySQL erweitert die Verwendung von GROUP BY, sodass die Auswahlliste auf nicht aggregierte Spalten verweisen kann, die nicht in der GROUP BY-Klausel aufgeführt sind. ... Mit dieser Funktion können Sie eine bessere Leistung erzielen, indem Sie unnötiges Sortieren und Gruppieren von Spalten vermeiden. Dies ist jedoch vor allem dann nützlich, wenn alle Werte in jeder nicht zusammengefassten Spalte, die nicht in GROUP BY angegeben sind, für jede Gruppe gleich sind. Der Server kann aus jeder Gruppe einen beliebigen Wert auswählen. Wenn diese Werte nicht gleich sind, sind die ausgewählten Werte unbestimmt. Außerdem kann die Auswahl von Werten aus jeder Gruppe nicht durch Hinzufügen einer ORDER BY-Klausel beeinflusst werden. Die Sortierung der Ergebnismenge erfolgt, nachdem Werte ausgewählt wurden, und ORDER BY hat keinen Einfluss auf die vom Server ausgewählten Werte.
Normalerweise erlaubt MySQL nur Datensätze in aufsteigender Reihenfolge. So können wir Datensätze vor der Gruppierung bestellen.
SELECT * FROM ( SELECT * FROM Fragen ORDER BY id DESC ) AS fragen GROUP BY fragen.asker
Die Datensätze müssen mit GROUP BY
und MAX()
gruppiert werden, um die maximale ID für jede asker
zu erhalten.
SELECT asker, MAX(ID) ID
FROM TableName
GROUP BY asker
AUSGABE
╔════════╦════╗
║ ASKER ║ ID ║
╠════════╬════╣
║ Bob ║ 2 ║
║ Marley ║ 3 ║
╚════════╩════╝
Bei den anderen ist die Verwendung von MAX (ID) korrekt, um die gewünschten Ergebnisse zu erhalten. Wenn Sie sich fragen, warum Ihre Abfrage nicht funktioniert, liegt dies daran, dass ORDER BY
after der GROUP BY
geschieht.
Ich schreibe diese Antwort, weil @ Taryns erste/kürzere Alternative in der akzeptierten Antwort nur funktioniert, wenn Sie genau die Spalten auswählen, die in GROUP BY und MAX verwendet werden. Der Benutzer, der eine Frage stellt, wählt alle Spalten in der Tabelle aus (er hat SELECT * verwendet). Wenn Sie also eine weitere dritte Spalte zur Tabelle hinzufügen, ist dieser Spaltenwert im Abfrageergebnis falsch. Sie erhalten gemischte Werte aus verschiedenen Tabellenzeilen. @ Taryns zweite/längere Alternative (mit innerem Join und Unterabfrage) funktioniert, aber die Abfrage ist unnötig kompliziert und ist in meinem Anwendungsfall fünfmal langsamer als meine einfache Alternative unten.
Betrachten Sie die Tabelle questions
:
id | asker
-----------
1 | Bob
2 | Bob
3 | Marley
Abfrage SELECT max(id) as id, asker FROM questions GROUP BY asker ORDER BY id DESC
gibt erwartet zurück:
id | asker
-----------
3 | Marley
2 | Bob
Betrachten Sie nun eine andere Tabelle questions
:
id | asker | other
-------------------
1 | Bob | 1st
2 | Bob | 2nd
3 | Marley | 3rd
Abfrage SELECT max(id) as id, asker, other FROM questions GROUP BY asker ORDER BY id DESC
gibt unerwartet zurück:
id | asker | other
-------------------
3 | Marley | 3rd
2 | Bob | 1st
... beachten Sie, dass der Wert von other
für die zweite Zeile des Ergebnisses falsch ist, da id=2
aus der zweiten Zeile der Tabelle stammt, aber other=1st
aus der ersten Zeile der Tabelle stammt! Auf diese Weise berichten viele Benutzer in Kommentaren von Taryns Antwort, dass diese Lösung nicht funktioniert.
Mögliche einfache Lösung, wenn Sie auch andere Spalten auswählen, ist die Verwendung von GROUP BY
+ DESC
:
SELECT id, asker, other FROM questions GROUP BY asker DESC
id | asker | other
-------------------
3 | Marley | 3rd
2 | Bob | 2nd
(Siehe Demo: https://www.db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/1 )
... aber diese einfache Lösung hat einige Einschränkungen:
asker
(ich denke, dies ist kein Problem, da Sie eine bessere Leistung erzielen, da der Index in diesem Fall geeignet ist. GROUP BY muss normalerweise erstellt werden der tmp-Tabelle, aber wenn ein Index verfügbar ist, wird keine tmp-Tabelle erstellt, was schneller ist)SET SESSION sql_mode = '';
) Oder ANY_VALUE()
für ausgewählte Spalten zu verwenden, die nicht aggregiert sind, um den Fehler ER_WRONG_FIELD_WITH_GROUP zu vermeiden.GROUP BY col1 ORDER BY col1 ASC/DESC
:SELECT id, asker, other FROM questions GROUP BY asker ORDER BY asker DESC
id | asker | other
-------------------
3 | Marley | 3rd
2 | Bob | 2nd
(Siehe Demo: https://www.db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/11 )
Das Ergebnis ist dasselbe wie oben mit GROUP BY ... DESC
(vergessen Sie nicht, InnoDB zu verwenden und einen Index zu erstellen).
Es ist, weil ORDER BY
wird ausgeführt NACH GROUP BY
.
Versuche dies:
SELECT * FROM questions
WHERE id IN
(
SELECT max(id) as id
FROM questions
GROUP by asker
ORDER by id DESC
)
Um jede Spalte zu erhalten:
SELECT * FROM questions
WHERE id IN
(SELECT max(id) as id, asker
FROM questions
GROUP by asker
ORDER by id DESC)
Verbesserte Version der Antwort von @bluefeet.