Die folgende Abfrage:
SELECT
year, id, rate
FROM h
WHERE year BETWEEN 2000 AND 2009
AND id IN (SELECT rid FROM table2)
GROUP BY id, year
ORDER BY id, rate DESC
Ausbeuten:
year id rate
2006 p01 8
2003 p01 7.4
2008 p01 6.8
2001 p01 5.9
2007 p01 5.3
2009 p01 4.4
2002 p01 3.9
2004 p01 3.5
2005 p01 2.1
2000 p01 0.8
2001 p02 12.5
2004 p02 12.4
2002 p02 12.2
2003 p02 10.3
2000 p02 8.7
2006 p02 4.6
2007 p02 3.3
Was ich möchte, sind nur die Top 5 Ergebnisse für jede ID:
2006 p01 8
2003 p01 7.4
2008 p01 6.8
2001 p01 5.9
2007 p01 5.3
2001 p02 12.5
2004 p02 12.4
2002 p02 12.2
2003 p02 10.3
2000 p02 8.7
Gibt es eine Möglichkeit, dies mit einem LIMIT-ähnlichen Modifikator zu tun, der innerhalb von GROUP BY funktioniert?
LIMIT
Klausel. Hier ist ein Artikel, der das Problem ausführlich erklärt: So wählen Sie die erste / kleinste / maximale Zeile pro Gruppe in SQL aus Es ist ein guter Artikel - er führt eine elegante, aber naive Lösung für das Problem "Top N pro Gruppe" ein und dann schrittweise verbessert es.Antworten:
Sie könnten verwenden GROUP_CONCAT aggregiert Funktion , um alle Jahre in einer einzigen Spalte zu erhalten, gruppiert nach
id
und geordnet nachrate
:Ergebnis:
Und dann könnten Sie FIND_IN_SET verwenden , das die Position des ersten Arguments innerhalb des zweiten zurückgibt, z.
Mit einer Kombination aus
GROUP_CONCAT
undFIND_IN_SET
und Filtern nach der von find_in_set zurückgegebenen Position können Sie dann diese Abfrage verwenden, die nur die ersten 5 Jahre für jede ID zurückgibt:Bitte sehen Sie Geige hier .
Beachten Sie, dass Sie, wenn mehr als eine Zeile dieselbe Rate haben kann, die Verwendung von GROUP_CONCAT (DISTINCT rate ORDER BY rate) in der Tarifspalte anstelle der Jahresspalte in Betracht ziehen sollten.
Die maximale Länge der von GROUP_CONCAT zurückgegebenen Zeichenfolge ist begrenzt. Dies funktioniert daher gut, wenn Sie für jede Gruppe einige Datensätze auswählen müssen.
quelle
SET SESSION group_concat_max_len = <maximum length>;
im Fall des OP ein Nicht-Problem verwenden (da der Standardwert 1024 ist), aber zum Beispiel sollte group_concat_max_len mindestens 25: 4 (max Länge einer Jahreszeichenfolge) + 1 (Trennzeichen), mal 5 (erste 5 Jahre). Die Zeichenfolgen werden abgeschnitten, anstatt einen Fehler auszulösen. Achten Sie daher auf Warnungen wie z1054 rows in set, 789 warnings (0.31 sec)
.FIND_IN_SET()
. Ich habe versucht,FIND_IN_SET() =2
aber nicht das erwartete Ergebnis zu zeigen.Die ursprüngliche Abfrage verwendete Benutzervariablen und
ORDER BY
abgeleitete Tabellen. Das Verhalten beider Macken ist nicht garantiert. Überarbeitete Antwort wie folgt.In MySQL 5.x können Sie den Rang eines armen Mannes über der Partition verwenden, um das gewünschte Ergebnis zu erzielen. Verbinden Sie die Tabelle einfach mit sich selbst und zählen Sie für jede Zeile die Anzahl der Zeilen, die kleiner als diese sind. Im obigen Fall ist die kleinere Reihe die mit der höheren Rate:
Demo und Ergebnis :
Beachten Sie, dass, wenn die Preise Bindungen hatten, zum Beispiel:
Die obige Abfrage gibt 6 Zeilen zurück:
Wechseln Sie zu
HAVING COUNT(DISTINCT l.rate) < 5
, um 8 Zeilen zu erhalten:Oder wechseln Sie zu
ON t.id = l.id AND (t.rate < l.rate OR (t.rate = l.rate AND t.pri_key > l.pri_key))
, um 5 Zeilen zu erhalten:In MySQL 8 oder verwenden Sie später nur die
RANK
,DENSE_RANK
oderROW_NUMBER
Funktionen:quelle
WHERE rank <=5
? Zum ersten Mal bekomme ich nicht 5 Zeilen von jeder ID, aber danach kann ich bekommen, wie du gesagt hast.SET
Aussage (siehe erste Abfrage). Es ist notwendig.ORDER BY
in der abgeleiteten Tabelle enthaltenen häufig ignoriert. Dies besiegt das Ziel. Effiziente gruppenweise finden Sie hier .ORDER BY
in solchen Lieferungen / Unterabfragen nie wirklich verwendet werden durften. Dies ist der Grund dafür Moderne MySQL / MariaDB-Versionen ignorieren dieORDER BY
In-Unterabfrage ohne VerwendungLIMIT
. Ich glaube, ANSI / ISO SQL-Standards 2008/2011/2016 machenORDER BY
Liefer- / Unterabfragen legal, wenn sie in Kombination mitFETCH FIRST n ROWS ONLY
Für mich so etwas wie
funktioniert perfekt. Keine komplizierte Abfrage.
Zum Beispiel: Holen Sie sich die Top 1 für jede Gruppe
quelle
Nein, Sie können Unterabfragen nicht willkürlich begrenzen (Sie können dies in neueren MySQLs in begrenztem Umfang tun, jedoch nicht für 5 Ergebnisse pro Gruppe).
Dies ist eine gruppenweise maximale Typabfrage, die in SQL nicht trivial ist. Es gibt verschiedene Möglichkeiten , um das anzugehen, was in einigen Fällen effizienter sein kann, aber für Top-n im Allgemeinen sollten Sie sich Bills Antwort auf eine ähnliche vorherige Frage ansehen .
Wie bei den meisten Lösungen für dieses Problem können mehr als fünf Zeilen zurückgegeben werden, wenn mehrere Zeilen mit demselben
rate
Wert vorhanden sind. Daher müssen Sie möglicherweise noch einige Nachbearbeitungen durchführen, um dies zu überprüfen.quelle
Dies erfordert eine Reihe von Unterabfragen, um die Werte zu ordnen, zu begrenzen und dann die Summe während der Gruppierung auszuführen
quelle
Versuche dies:
quelle
Die Unterabfrage ist fast identisch mit Ihrer Abfrage. Nur die Änderung wird hinzugefügt
quelle
ROW_NUMBER()
).row_number()
ist verfügbar .Erstellen Sie die virtuellen Spalten (wie RowID in Oracle)
Tabelle:
Daten:
SQL wie folgt:
Wenn Sie die where-Klausel in t3 löschen, wird Folgendes angezeigt:
GET "TOP N Record" -> füge das "rownum <= 3" in die where-Klausel (die where-Klausel von t3) ein;
WÄHLEN SIE "das Jahr" -> fügen Sie das "ZWISCHEN 2000 UND 2009" in die where-Klausel (die where-Klausel von t3) ein;
quelle
Es hat einige Arbeit gekostet, aber ich denke, meine Lösung wäre etwas zu teilen, da sie sowohl elegant als auch recht schnell erscheint.
Beachten Sie, dass dieses Beispiel für den Zweck der Frage angegeben wurde und für andere ähnliche Zwecke recht einfach geändert werden kann.
quelle
Der folgende Beitrag: sql: Die Auswahl des Top-N-Datensatzes pro Gruppe beschreibt die komplizierte Methode, um dies ohne Unterabfragen zu erreichen.
Es verbessert andere hier angebotene Lösungen von:
Es ist jedoch nicht schön. Eine gute Lösung wäre erreichbar, wenn Fensterfunktionen (auch als analytische Funktionen bezeichnet) in MySQL aktiviert wären - dies ist jedoch nicht der Fall. Der in diesem Beitrag verwendete Trick verwendet GROUP_CONCAT, das manchmal als "Fensterfunktionen des armen Mannes für MySQL" bezeichnet wird.
quelle
für diejenigen wie mich, die eine Auszeit hatten. Ich habe das Folgende gemacht, um Grenzen und alles andere von einer bestimmten Gruppe zu verwenden.
Es durchläuft eine Liste von Domänen und fügt dann jeweils nur ein Limit von 200 ein
quelle
Versuche dies:
quelle
Bitte versuchen Sie es mit der unten gespeicherten Prozedur. Ich habe bereits überprüft. Ich erhalte das richtige Ergebnis, aber ohne es zu verwenden
groupby
.quelle