group-by group - MySQL "Gruppieren nach" und "Bestellen nach"





order having (6)


Wie schon in einer Antwort darauf hingewiesen wurde, ist die aktuelle Antwort falsch, da GROUP BY den Datensatz aus dem Fenster willkürlich auswählt.

Wenn man MySQL 5.6 oder MySQL 5.7 mit ONLY_FULL_GROUP_BY , ist die korrekte (deterministische) Abfrage:

SELECT incomingEmails.*
  FROM (
    SELECT fromEmail, MAX(timestamp) `timestamp`
    FROM incomingEmails
    GROUP BY fromEmail
  ) filtered_incomingEmails
  JOIN incomingEmails USING (fromEmail, timestamp)
GROUP BY fromEmail, timestamp

Damit die Abfrage effizient ausgeführt werden kann, ist eine ordnungsgemäße Indizierung erforderlich.

Beachten Sie, dass ich zur Vereinfachung den LOWER() , der in den meisten Fällen nicht verwendet wird.

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 Abfrage sieht so 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 nach E-Mail gruppiert sind. Das Problem besteht darin, dass der Betreff und der Zeitstempel nicht dem neuesten Datensatz für eine bestimmte E-Mail-Adresse entsprechen.

Zum Beispiel könnte es zurückkehren:

fromEmail: [email protected], subject: hello
fromEmail: [email protected], subject: welcome

Wenn die Datensätze in der Datenbank sind:

fromEmail: [email protected], subject: hello
fromEmail: [email protected], subject: programming question
fromEmail: [email protected], subject: welcome

Wenn der Betreff "Programmierfrage" der neueste ist, wie kann ich diesen Datensatz beim Gruppieren der E-Mails auswählen?




Gemäß dem SQL-Standard können Sie keine nicht aggregierten Spalten in der Auswahlliste verwenden. MySQL erlaubt solche Verwendung (Uless ONLY_FULL_GROUP_BY Modus verwendet), aber das Ergebnis ist nicht vorhersehbar.

ONLY_FULL_GROUP_BY

Sie sollten zuerst aus E-Mail, MIN (lesen) und dann mit zweiter Abfrage (oder Unterabfrage) - Betreff auswählen.




Eine einfache Lösung besteht darin, die Abfrage zunächst mit der ORDER-Anweisung in einen Subselect zu packen und später GROUP BY anzuwenden:

SELECT * FROM ( 
    SELECT `timestamp`, `fromEmail`, `subject`
    FROM `incomingEmails` 
    ORDER BY `timestamp` DESC
) AS tmp_table GROUP BY LOWER(`fromEmail`)

Dies ist ähnlich wie bei der Verknüpfung, sieht aber viel schöner aus.

Die Verwendung von Nicht-Aggregatspalten in einem SELECT mit einer GROUP BY-Klausel ist nicht standardisiert. MySQL gibt normalerweise die Werte der ersten gefundenen Zeile zurück und verwirft den Rest. Alle ORDER BY-Klauseln gelten nur für den zurückgegebenen Spaltenwert, nicht für die verworfenen.

WICHTIGE AKTUALISIERUNG Die Auswahl von Nicht-Aggregat-Spalten, die in der Praxis verwendet wurden, sollte aber nicht verlässlich sein. Laut der MySQL-Dokumentation "ist dies in erster Linie nützlich, wenn alle Werte in jeder nichtaggregierten Spalte, die nicht in GROUP BY benannt sind, für jede Gruppe gleich sind. Der Server kann aus jeder Gruppe einen beliebigen Wert auswählen , wenn sie nicht gleich sind gewählt sind unbestimmt . "

Ab 5.6.21 habe ich Probleme mit der GROUP BY in der temporären Tabelle festgestellt, die die ORDER BY-Sortierung zurücksetzt.

Ab 5.7.5 ist 5.7.5 standardmäßig aktiviert, dh es ist nicht möglich, nicht aggregierte Spalten zu verwenden.

Siehe http://www.cafewebmaster.com/mysql-order-sort-group https://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html 5.7.5




Hier ist ein Ansatz:

SELECT cur.textID, cur.fromEmail, cur.subject, 
     cur.timestamp, cur.read
FROM incomingEmails cur
LEFT JOIN incomingEmails next
    on cur.fromEmail = next.fromEmail
    and cur.timestamp < next.timestamp
WHERE next.timestamp is null
and cur.toUserID = '$userID' 
ORDER BY LOWER(cur.fromEmail)

Im Grunde treten Sie der Tabelle bei 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 es mehrere E-Mails mit demselben Zeitstempel geben kann, müsste diese Abfrage verfeinert werden. Wenn eine inkrementelle ID-Spalte in der E-Mail-Tabelle vorhanden ist, ändern Sie den JOIN wie folgt:

LEFT JOIN incomingEmails next
    on cur.fromEmail = next.fromEmail
    and cur.id < next.id



Führen Sie nach dem ORDER BY eine GROUP BY aus, indem Sie Ihre Abfrage mit GROUP BY wie folgt umschließen:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t GROUP BY t.from



Sie können dies auch versuchen.

var results= persons.GroupBy(n => new { n.PersonId, n.car})
                .Select(g => new {
                               g.Key.PersonId,
                               g.Key.car)}).ToList();




sql mysql group-by sql-order-by