Eine Möglichkeit besteht darin, eine Rangvariable wie die folgende zu verwenden:
SELECT first_name,
age,
gender,
@curRank := @curRank + 1 AS rank
FROM person p, (SELECT @curRank := 0) r
ORDER BY age;
Das (SELECT @curRank := 0)
Teil ermöglicht die Variableninitialisierung, ohne dass eine separate erforderlich istSET
Befehl .
Testfall:
CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1));
INSERT INTO person VALUES (1, 'Bob', 25, 'M');
INSERT INTO person VALUES (2, 'Jane', 20, 'F');
INSERT INTO person VALUES (3, 'Jack', 30, 'M');
INSERT INTO person VALUES (4, 'Bill', 32, 'M');
INSERT INTO person VALUES (5, 'Nick', 22, 'M');
INSERT INTO person VALUES (6, 'Kathy', 18, 'F');
INSERT INTO person VALUES (7, 'Steve', 36, 'M');
INSERT INTO person VALUES (8, 'Anne', 25, 'F');
Ergebnis:
+------------+------+--------+------+
| first_name | age | gender | rank |
+------------+------+--------+------+
| Kathy | 18 | F | 1 |
| Jane | 20 | F | 2 |
| Nick | 22 | M | 3 |
| Bob | 25 | M | 4 |
| Anne | 25 | F | 5 |
| Jack | 30 | M | 6 |
| Bill | 32 | M | 7 |
| Steve | 36 | M | 8 |
+------------+------+--------+------+
8 rows in set (0.02 sec)
partition by gender
Teil der Analysefunktion fehlt (der denHier ist eine generische Lösung, die Zeilen einen dichten Rang über der Partition zuweist. Es werden Benutzervariablen verwendet:
Beachten Sie, dass die Variablenzuweisungen innerhalb des
CASE
Ausdrucks platziert werden. Dies kümmert sich (theoretisch) um die Reihenfolge der Bewertung. DasIS NOT NULL
wird hinzugefügt, um Probleme mit der Datentypkonvertierung und dem Kurzschluss zu lösen.PS: Es kann einfach über die Partition in eine Zeilennummer konvertiert werden, indem alle Bedingungen entfernt werden, die auf Gleichheit prüfen.
Demo auf db <> fiddle
quelle
ELSE @rank_count := @rank_count + 1
ORDER BY gender, age DESC
?Während die am besten bewertete Antwort rangiert, wird sie nicht partitioniert. Sie können einen Self-Join durchführen, um das Ganze auch zu partitionieren:
Anwendungsfall
Antwort :
quelle
Eine Optimierung von Daniels Version, um das Perzentil zusammen mit dem Rang zu berechnen. Auch zwei Personen mit den gleichen Noten erhalten den gleichen Rang.
Ergebnisse der Abfrage nach Beispieldaten -
quelle
Kombination von Daniels und Salmans Antwort. Der Rang wird jedoch nicht angegeben, da eine fortlaufende Sequenz mit Bindungen besteht. Stattdessen wird der Rang zum nächsten übersprungen. So erreichen Sie maximal immer die Zeilenanzahl.
Schema und Testfall:
Ausgabe:
quelle
Ab MySQL 8 können Sie endlich auch in MySQL Fensterfunktionen verwenden: https://dev.mysql.com/doc/refman/8.0/en/window-functions.html
Ihre Anfrage kann genauso geschrieben werden:
quelle
@Sam, Ihr Punkt ist im Konzept ausgezeichnet, aber ich denke, Sie haben falsch verstanden, was die MySQL-Dokumente auf der referenzierten Seite sagen - oder ich verstehe falsch :-) - und ich wollte dies nur hinzufügen, damit sich jemand mit dem @ unwohl fühlt Daniels Antwort, sie werden beruhigter sein oder zumindest etwas tiefer graben.
Sie sehen, dass das
"@curRank := @curRank + 1 AS rank"
InnereSELECT
nicht "eine Aussage" ist, sondern ein "atomarer" Teil der Aussage, also sollte es sicher sein.Das Dokument, auf das Sie verweisen, zeigt Beispiele, in denen dieselbe benutzerdefinierte Variable in zwei (atomaren) Teilen der Anweisung verwendet wird, z.
"SELECT @curRank, @curRank := @curRank + 1 AS rank"
.Man könnte argumentieren, dass dies
@curRank
in @ Daniels Antwort zweimal verwendet wird: (1) die"@curRank := @curRank + 1 AS rank"
und (2) die,"(SELECT @curRank := 0) r"
aber da die zweite Verwendung Teil der istFROM
Klausel ist, bin ich mir ziemlich sicher, dass sie garantiert zuerst bewertet wird; im Wesentlichen macht es eine zweite und vorhergehende Aussage.Tatsächlich sehen Sie auf derselben MySQL-Dokumentenseite, auf die Sie verwiesen haben, dieselbe Lösung in den Kommentaren - es könnte sein, woher @Daniel sie hat; Ja, ich weiß, dass es die Kommentare sind, aber es sind Kommentare auf der offiziellen Dokumentenseite und das hat etwas Gewicht.
quelle
Die einfachste Lösung, um den Rang eines bestimmten Werts zu bestimmen, besteht darin, die Anzahl der Werte davor zu zählen . Angenommen, wir haben die folgenden Werte:
30
Werte gelten als 3 ..40
Werte werden als 6. (Rang) oder 4. (dichter Rang) betrachtet.Nun zurück zur ursprünglichen Frage. Hier sind einige Beispieldaten, die wie in OP beschrieben sortiert sind (erwartete Ränge werden rechts hinzugefügt):
Zu berechnen
RANK() OVER (PARTITION BY Gender ORDER BY Age)
für Sarah, können Sie diese Abfrage verwenden:Zu berechnen
RANK() OVER (PARTITION BY Gender ORDER BY Age)
für alle Zeilen, können Sie diese Abfrage verwenden:Und hier ist das Ergebnis (verbundene Werte werden rechts hinzugefügt):
quelle
Wenn Sie nur eine Person bewerten möchten, können Sie Folgendes tun:
Diese Rangfolge entspricht der Orakel-RANG-Funktion (Wenn Personen mit demselben Alter denselben Rang erhalten und die Rangfolge danach nicht fortlaufend ist).
Es ist ein bisschen schneller als die Verwendung einer der oben genannten Lösungen in einer Unterabfrage und die Auswahl daraus, um das Ranking einer Person zu erhalten.
Dies kann verwendet werden, um alle zu bewerten, ist jedoch langsamer als die oben genannten Lösungen.
quelle
Person
Tabelle zunimmt. Es ist O (n ^ 2) gegen O (n) langsamer.Um das " jedoch " in Erandacs Antwort in Kombination mit Daniels und Salmans Antworten zu vermeiden , kann eine der folgenden "Partition Workarounds" verwendet werden.
Das Partitionsranking in der 3. Variante in diesem Code-Snippet gibt fortlaufende Ranking-Nummern zurück. Dies führt zu einer Datenstruktur ähnlich dem
rank() over partition by
Ergebnis. Als Beispiel siehe unten. Insbesondere beginnt die partitionSequence immer mit 1 für jeden neuen partitionRank , wobei folgende Methode verwendet wird:quelle
quelle