wake-up-neo.net

Wie gruppiere ich nach DESC-Auftrag

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

18
Michael Samuel

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.

36
Taryn

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 
18
Kapil dev

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 ║
╚════════╩════╝
3
John Woo

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.

1
Michael L.

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:

  • Die Tabelle muss InnoDB sein (ich denke, es ist kein Problem, weil Sie eine bessere Leistung erzielen und weil MySQL> = 5.5.5 Standard/Bevorzugte Speicher-Engine von MyISAM auf InnoDB geändert wurde)
  • Sie müssen einen Index für die Spalte erstellen, die in GROUP BY verwendet wird - in diesem Fall also 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)
  • Für MySQL 5.7 und 8.0 ist es erforderlich, den SQL-Modus ONLY_FULL_GROUP_BY zu deaktivieren (z. B. 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.
  • Leider haben MySQL-Entwickler die Unterstützung von ASC/DESC mit GROUP BY seit MySQL 8.0 entfernt https://dev.mysql.com/worklog/task/?id=869 aber zum Glück gibt es eine Alternative 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).

0
mikep

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
)
0
evilReiko

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.

0
Olimjon