Gibt es in MySQL eine gute Möglichkeit, die SQL Server-Funktion zu replizieren ROW_NUMBER()
?
Beispielsweise:
SELECT
col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1
Dann könnte ich zum Beispiel eine Bedingung hinzufügen, die intRow
auf 1 begrenzt ist, um eine einzelne Zeile mit der höchsten col3
für jedes (col1, col2)
Paar zu erhalten.
greatest-n-per-group
, um Sie zu ähnlichen Fragen zu führen.Sql-Server
Tag wurde entfernt, da dies das Element mit der höchsten Bewertung in der kombinierten Tag-Suche war, aber für SQL Server nicht wirklich relevant ist.Antworten:
Das ist ein gruppenweises Maximum , eine der am häufigsten gestellten SQL-Fragen (da es so scheint, als ob es einfach sein sollte, aber eigentlich nicht).
Ich plumpse oft für einen Null-Self-Join:
"Holen Sie sich die Zeilen in der Tabelle, für die keine andere Zeile mit übereinstimmendem col1, col2 ein höheres col3 hat." (Sie werden feststellen, dass diese und die meisten anderen gruppenweise maximalen Lösungen mehrere Zeilen zurückgeben, wenn mehr als eine Zeile dieselbe Spalte1, Spalte2, Spalte3 hat. Wenn dies ein Problem ist, müssen Sie möglicherweise nachbearbeitet werden.)
quelle
SELECT t1.id FROM test t1 LEFT JOIN test t2 ON t1.id>t2.id WHERE t2.id IS NULL;
Erfordert es keinen*n/2 + n/2
IS NULL-Vergleiche, um die einzelne Zeile zu finden? Gibt es Optimierungen, die ich nicht sehe? Ich habe versucht, Bill in einem anderen Thread eine ähnliche Frage zu stellen, aber er scheint sie ignoriert zu haben.SELECT t0.col3 FROM table AS t0 WHERE NOT EXISTS (select 1 from table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3)
In MySQL gibt es keine Ranking-Funktionalität. Am nächsten können Sie eine Variable verwenden:
Ja. Wenn es Oracle wäre, könnten Sie die LEAD-Funktion verwenden, um den nächsten Wert zu erreichen. Zum Glück behandelt Quassnoi die Logik für das, was Sie in MySQL implementieren müssen .
quelle
SELECT @row_num:=@row_num+1 AS row_number, t.id FROM (SELECT * FROM table1 WHERE col = 264 ORDER BY id) t, (SELECT @row_num:=0) var;
Am Ende folge ich immer diesem Muster. Angesichts dieser Tabelle:
Sie können dieses Ergebnis erhalten:
Durch Ausführen dieser Abfrage, für die keine Variable definiert werden muss:
Ich hoffe, das hilft!
quelle
<
,>
,<=
,>=
handle CHAR und VARCHAR Datentypen auf alphabetischer Reihenfolge; Ich erwarte, ist genau das, wonach Sie suchen.row_numbers <= 2
Und vielen Dank für diese Antwort Mosty, es ist perfekt!quelle
In diesem Artikel wird gezeigt, wie SQL ROW_NUMBER () mit einer Partition in MySQL nachgeahmt wird. Ich bin in einer WordPress-Implementierung auf dasselbe Szenario gestoßen. Ich brauchte ROW_NUMBER () und es war nicht da.
http://www.explodybits.com/2011/11/mysql-row-number/
Das Beispiel im Artikel verwendet eine einzelne Partition nach Feld. Um nach zusätzlichen Feldern zu partitionieren, können Sie Folgendes tun:
Die Verwendung von concat_ws behandelt Nullen. Ich habe dies anhand von 3 Feldern mit int, date und varchar getestet. Hoffe das hilft. Lesen Sie den Artikel, in dem diese Abfrage aufgeschlüsselt und erläutert wird.
quelle
limit 18446744073709551615
die Force-order by
Klausel hinzu.concat_ws
mit leerer Schnur''
ist gefährlich :concat_ws('',12,3) = concat_ws('',1,23)
. Verwenden Sie besser ein Trennzeichen'_'
oder eine @ Kenneth Xu-Lösung.Von
MySQL 8.0.0
und über können Sie nativ Fensterfunktionen verwenden.1.4 Was ist neu in MySQL 8.0 :
ROW_NUMBER () over_clause :
Demo:
DBFiddle Demo
quelle
Ich würde auch für Mosty Mostachos Lösung mit geringfügigen Änderungen an seinem Abfragecode stimmen:
Welches ergibt das gleiche Ergebnis:
für den Tisch:
Mit dem einzigen Unterschied, dass die Abfrage JOIN und GROUP BY nicht verwendet und stattdessen auf verschachtelte Auswahl setzt.
quelle
Ich würde eine Funktion definieren:
dann könnte ich tun:
Jetzt haben Sie keine Unterabfrage, die Sie in Ansichten nicht haben können.
quelle
Abfrage nach Zeilennummer in MySQL
quelle
Es gibt keine funtion wie
rownum
,row_num()
in MySQL , aber die Art und Weise um ist wie folgt:quelle
Die Lösung, die ich am besten fand, war die Verwendung einer Unterabfrage wie dieser:
Die PARTITION BY-Spalten werden nur mit '=' verglichen und durch AND getrennt. Die ORDER BY-Spalten werden mit '<' oder '>' verglichen und durch OR getrennt.
Ich habe festgestellt, dass dies sehr flexibel ist, auch wenn es ein bisschen teuer ist.
quelle
Die Rownumber-Funktionalität kann nicht nachgeahmt werden. Möglicherweise erhalten Sie die erwarteten Ergebnisse, aber höchstwahrscheinlich werden Sie irgendwann enttäuscht. In der MySQL-Dokumentation heißt es:
Grüße, Georgi.
quelle
MariaDB 10.2 implementiert "Fensterfunktionen", einschließlich RANK (), ROW_NUMBER () und mehrerer anderer Dinge:
https://mariadb.com/kb/en/mariadb/window-functions/
Basierend auf einem Vortrag bei Percona Live in diesem Monat sind sie einigermaßen gut optimiert.
Die Syntax ist identisch mit dem Code in der Frage.
quelle
Ich sehe keine einfache Antwort für den Teil "PARTITION BY". Hier ist meine:
In diesem einfachen Beispiel habe ich nur einen eingefügt, aber Sie können mehrere "PARTITION BY" -Teile haben
quelle
Ein bisschen spät, kann aber auch jemandem helfen, der nach Antworten sucht ...
Beispiel zwischen Zeilen / Zeilennummer - rekursive Abfrage, die in jedem SQL verwendet werden kann:
quelle
Dies ermöglicht die gleiche Funktionalität, die ROW_NUMBER () AND PARTITION BY bietet, in MySQL
quelle
Auch ein bisschen spät, aber heute hatte ich das gleiche Bedürfnis, also suchte ich bei Google und fand schließlich einen einfachen allgemeinen Ansatz hier in Pinal Daves Artikel http://blog.sqlauthority.com/2014/03/09/mysql-reset-row -Nummer-für-jede-Gruppe-Partition-nach-Zeilennummer /
Ich wollte mich auf Pauls ursprüngliche Frage konzentrieren (das war auch mein Problem), also fasse ich meine Lösung als Arbeitsbeispiel zusammen.
Da wir über zwei Spalten partitionieren möchten, würde ich während der Iteration eine SET-Variable erstellen, um festzustellen, ob eine neue Gruppe gestartet wurde.
Die 3 bedeutet beim ersten Parameter von MAKE_SET, dass ich beide Werte im SET haben möchte (3 = 1 | 2). Wenn wir nicht zwei oder mehr Spalten haben, die die Gruppen bilden, können wir natürlich die Operation MAKE_SET eliminieren. Die Konstruktion ist genau die gleiche. Dies funktioniert bei mir nach Bedarf. Vielen Dank an Pinal Dave für seine klare Demonstration.
quelle
ORDER BY
in einer Unterabfrage ignoriert werden kann (siehe mariadb.com/kb/en/mariadb/… ). Die vorgeschlagene Lösung besteht darinLIMIT 18446744073709551615
, der Unterabfrage etwas hinzuzufügen, wodurch eine Sortierung erzwungen wird. Dies kann jedoch zu Leistungsproblemen führen und gilt nicht für wirklich verdammt große Tische :)Dies könnte auch eine Lösung sein:
quelle
MySQL unterstützt ROW_NUMBER () seit Version 8.0+ .
Wenn Sie MySQL 8.0 oder höher verwenden, überprüfen Sie die Funktion ROW_NUMBER (). Andernfalls haben Sie die Funktion ROW_NUMBER () emuliert.
Die row_number () ist eine Rangfolgefunktion, die eine fortlaufende Nummer einer Zeile zurückgibt, beginnend mit 1 für die erste Zeile.
für ältere Version,
quelle
Wichtig: Bitte erwägen Sie ein Upgrade auf MySQL 8+ und verwenden Sie die definierte und dokumentierte Funktion ROW_NUMBER (). Lassen Sie alte Hacks hinter sich, die an eine funktionsbeschränkte alte Version von MySQL gebunden sind
Hier ist einer dieser Hacks:
Die Antworten hier, die meistens / alle Abfragevariablen verwenden, scheinen die Tatsache zu ignorieren, dass in der Dokumentation steht (Paraphrase):
Als solches besteht das Risiko, dass sie die falsche Antwort ausgeben, weil sie normalerweise eine Antwort geben
Wenn diese jemals von unten nach oben ausgewertet werden, funktioniert die Zeilennummer nicht mehr (keine Partitionen).
Wir müssen also etwas mit einer garantierten Ausführungsreihenfolge verwenden. Geben Sie CASE WHEN ein:
Als Gliederung ld ist die Reihenfolge der Zuweisung von prevcol wichtig - prevcol muss mit dem Wert der aktuellen Zeile verglichen werden, bevor wir ihm einen Wert aus der aktuellen Zeile zuweisen (andernfalls wäre es der Spaltenwert der aktuellen Zeilen, nicht der Spaltenwert der vorherigen Zeile). .
So passt das zusammen:
Das erste WANN wird ausgewertet. Wenn die Spalte dieser Zeile mit der Spalte der vorherigen Zeile übereinstimmt, wird @r inkrementiert und vom CASE zurückgegeben. Diese LED-Rückgabewerte werden in @r gespeichert. Es ist eine Funktion von MySQL, dass die Zuweisung den neuen Wert dessen, was in @r zugewiesen ist, in die Ergebniszeilen zurückgibt.
Für die erste Zeile in der Ergebnismenge ist @prevcol null (es wird in der Unterabfrage auf null initialisiert), daher ist dieses Prädikat falsch. Dieses erste Prädikat gibt bei jeder Änderung der Spalte auch false zurück (die aktuelle Zeile unterscheidet sich von der vorherigen Zeile). Dies bewirkt, dass das zweite WANN ausgewertet wird.
Das zweite WHEN-Prädikat ist immer falsch und dient lediglich dazu, @prevcol einen neuen Wert zuzuweisen. Da sich die Spalte dieser Zeile von der Spalte der vorherigen Zeile unterscheidet (wir wissen dies, weil bei gleicher Verwendung das erste WANN verwendet worden wäre), müssen wir den neuen Wert zuweisen, damit er beim nächsten Test beibehalten wird. Da die Zuweisung vorgenommen wird und dann das Ergebnis der Zuweisung mit null verglichen wird und alles, was mit null gleichgesetzt wird, falsch ist, ist dieses Prädikat immer falsch. Zumindest die Auswertung hat jedoch dazu beigetragen, den Wert von col aus dieser Zeile beizubehalten, sodass er anhand des col-Werts der nächsten Zeile ausgewertet werden kann
Da das zweite WHEN falsch ist, bedeutet dies, dass in Situationen, in denen sich die Spalte, nach der wir partitionieren (col), geändert hat, ELSE einen neuen Wert für @r angibt und die Nummerierung von 1 neu startet
Wir kommen zu einer Situation, in der dies:
Hat die allgemeine Form:
Fußnoten:
Das p in pcol bedeutet "Partition", das o in ocol bedeutet "Reihenfolge" - in der allgemeinen Form habe ich das "prev" aus dem Variablennamen entfernt, um die visuelle Unordnung zu verringern
Die Klammern
(@pcolX := colX) = null
sind wichtig. Ohne sie weisen Sie @pcolX null zu und die Dinge funktionieren nicht mehrEs ist ein Kompromiss, dass die Ergebnismenge auch nach den Partitionsspalten sortiert werden muss, damit der Vergleich der vorherigen Spalte funktioniert. Sie können Ihre Rownumber daher nicht nach einer Spalte sortieren lassen, sondern Ihre Ergebnismenge nach einer anderen. Möglicherweise können Sie dies mit Unterabfragen beheben. Ich glaube jedoch, dass in den Dokumenten auch angegeben ist, dass die Reihenfolge der Unterabfragen ignoriert werden kann, sofern nicht LIMIT verwendet wird und dies Auswirkungen haben könnte Performance
Ich habe mich nicht weiter damit befasst, als zu testen, ob die Methode funktioniert, aber wenn das Risiko besteht, dass die Prädikate im zweiten WANN wegoptimiert werden (alles im Vergleich zu null ist null / falsch, warum also die Aufgabe ausführen) und nicht ausgeführt werden hört es auch auf. Dies scheint meiner Erfahrung nach nicht zu geschehen, aber ich nehme gerne Kommentare an und schlage eine Lösung vor, wenn dies vernünftigerweise möglich ist
Es kann sinnvoll sein, die Nullen, mit denen @pcolX erstellt wird, in die tatsächlichen Typen Ihrer Spalten in der Unterabfrage umzuwandeln, mit der die Variablen @pcolX erstellt werden.
select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
quelle
Dies ist nicht die robusteste Lösung. Wenn Sie jedoch nur einen partitionierten Rang in einem Feld mit nur wenigen unterschiedlichen Werten erstellen möchten, ist es möglicherweise nicht unhandlich, einen Fall zu verwenden, wenn Logik mit so vielen Variablen wie erforderlich benötigt wird.
So etwas hat in der Vergangenheit bei mir funktioniert:
Hoffe das macht Sinn / hilft!
quelle
Dies funktioniert perfekt für mich, um RowNumber zu erstellen, wenn wir mehr als eine Spalte haben. In diesem Fall zwei Spalten.
quelle
quelle
quelle