Ich möchte in der Lage sein, eine Reihe von Zeilen aus einer Tabelle von E-Mails auszuwählen und sie nach dem Absender zu gruppieren. Meine Anfrage sieht folgendermaßen aus:
SELECT
`timestamp`, `fromEmail`, `subject`
FROM `incomingEmails`
GROUP BY LOWER(`fromEmail`)
ORDER BY `timestamp` DESC
Die Abfrage funktioniert fast so, wie ich es möchte - sie wählt Datensätze aus, die per E-Mail gruppiert sind. Das Problem ist, dass Betreff und Zeitstempel nicht dem neuesten Datensatz für eine bestimmte E-Mail-Adresse entsprechen.
Zum Beispiel könnte es zurückgeben:
fromEmail: john@example.com, subject: hello
fromEmail: mark@example.com, subject: welcome
Wenn die Datensätze in der Datenbank sind:
fromEmail: john@example.com, subject: hello
fromEmail: john@example.com, subject: programming question
fromEmail: mark@example.com, subject: welcome
Wenn das Thema "Programmierfrage" das aktuellste ist, wie kann ich MySQL veranlassen, diesen Datensatz beim Gruppieren der E-Mails auszuwählen?
quelle
As of 5.7.5 ONLY_FULL_GROUP_BY is enabled by default, i.e. it's impossible to use non-aggregate columns.
Der SQL-Modus kann zur Laufzeit ohne Administratorrechte geändert werden, sodass ONLY_FULL_GROUP_BY sehr einfach deaktiviert werden kann. Zum Beispiel :SET SESSION sql_mode = '';
. Demo: db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/3Hier ist ein Ansatz:
Grundsätzlich verbinden Sie die Tabelle selbst und suchen nach späteren Zeilen. In der where-Klausel geben Sie an, dass es keine späteren Zeilen geben darf. Dies gibt Ihnen nur die letzte Zeile.
Wenn mehrere E-Mails mit demselben Zeitstempel vorhanden sein können, muss diese Abfrage verfeinert werden. Wenn die E-Mail-Tabelle eine inkrementelle ID-Spalte enthält, ändern Sie den JOIN wie folgt:
quelle
textID
sei mehrdeutig = /LEFT JOIN
Kriterien eine weitere Bedingung hinzufügen, um die Ergebnismenge auf nicht zukünftige Daten zu beschränkenAND next.timestamp <= UNIX_TIMESTAMP()
Wie bereits in einer Antwort erwähnt, ist die aktuelle Antwort falsch, da GROUP BY den Datensatz willkürlich aus dem Fenster auswählt.
Wenn man MySQL 5.6 oder MySQL 5.7 mit verwendet
ONLY_FULL_GROUP_BY
, lautet die richtige (deterministische) Abfrage:Damit die Abfrage effizient ausgeführt werden kann, ist eine ordnungsgemäße Indizierung erforderlich.
Beachten Sie, dass ich zur Vereinfachung das entfernt habe
LOWER()
, was in den meisten Fällen nicht verwendet wird.quelle
order by
in der Unterauswahl in den anderen Antworten hat überhaupt keine Auswirkung.Führen Sie nach ORDER BY ein GROUP BY durch, indem Sie Ihre Abfrage wie folgt mit GROUP BY umschließen:
quelle
time
oder die neuestetime
oder zufällige aus?time DESC
und dann die Gruppe nach die erste (späteste).Gemäß dem SQL-Standard können Sie keine nicht aggregierten Spalten in der Auswahlliste verwenden. MySQL erlaubt eine solche Verwendung (uless ONLY_FULL_GROUP_BY-Modus verwendet), aber das Ergebnis ist nicht vorhersehbar.
ONLY_FULL_GROUP_BY
Sie sollten zuerst E-Mail, MIN (Lesen) und dann mit der zweiten Abfrage (oder Unterabfrage) - Betreff auswählen.
quelle
Ich kämpfte mit diesen beiden Ansätzen um komplexere Abfragen als die gezeigten, weil der Unterabfrageansatz schrecklich unzulänglich war, egal welche Indizes ich anlegte, und weil ich die äußere Selbstverbindung nicht durch den Ruhezustand erreichen konnte
Der beste (und einfachste) Weg, dies zu tun, besteht darin, nach etwas zu gruppieren, das eine Verkettung der benötigten Felder enthält, und sie dann mithilfe von Ausdrücken in der SELECT-Klausel herauszuziehen. Wenn Sie MAX () ausführen müssen, stellen Sie sicher, dass sich das Feld, über das Sie MAX () senden möchten, immer am wichtigsten Ende der verketteten Entität befindet.
Der Schlüssel zum Verständnis ist, dass die Abfrage nur dann sinnvoll sein kann, wenn diese anderen Felder für eine Entität unveränderlich sind, die Max () erfüllt. In Bezug auf die Sortierung können die anderen Teile der Verkettung ignoriert werden. Wie das geht, erfahren Sie ganz unten in diesem Link. http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html
Wenn Sie ein Einfüge- / Aktualisierungsereignis (wie einen Auslöser) erhalten, um die Verkettung der Felder vorab zu berechnen, können Sie es indizieren, und die Abfrage ist so schnell, als ob die Gruppe nach nur über dem Feld wäre, das Sie tatsächlich MAX ( ). Sie können es sogar verwenden, um das Maximum aus mehreren Feldern zu erhalten. Ich verwende es, um Abfragen für mehrdimensionale Bäume durchzuführen, die als verschachtelte Mengen ausgedrückt werden.
quelle