MySQL - Zeilennummer bei Auswahl abrufen


181

Kann ich eine select-Anweisung ausführen und die Zeilennummer abrufen, wenn die Elemente sortiert sind?

Ich habe einen Tisch wie diesen:

mysql> describe orders;
+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| orderID     | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| itemID      | bigint(20) unsigned | NO   |     | NULL    |                |
+-------------+---------------------+------+-----+---------+----------------+

Ich kann diese Abfrage dann ausführen, um die Anzahl der Bestellungen nach ID zu ermitteln:

SELECT itemID, COUNT(*) as ordercount
FROM orders
GROUP BY itemID ORDER BY ordercount DESC;

Dies gibt mir eine Zählung von jedem itemIDin der Tabelle wie folgt:

+--------+------------+
| itemID | ordercount |
+--------+------------+
|    388 |          3 |
|    234 |          2 |
|   3432 |          1 |
|    693 |          1 |
|   3459 |          1 |
+--------+------------+

Ich möchte auch die Zeilennummer erhalten, damit ich feststellen kann, dass itemID=388es sich um die erste Zeile, 234die zweite usw. handelt (im Wesentlichen die Rangfolge der Bestellungen, nicht nur eine Rohzählung). Ich weiß, dass ich dies in Java tun kann, wenn ich die Ergebnismenge zurückerhalte, aber ich habe mich gefragt, ob es eine Möglichkeit gibt, dies nur in SQL zu handhaben.

Aktualisieren

Durch Festlegen des Ranges wird dieser zur Ergebnismenge hinzugefügt, jedoch nicht richtig geordnet:

mysql> SET @rank=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
    -> FROM orders
    -> GROUP BY itemID ORDER BY rank DESC;
+------+--------+------------+
| rank | itemID | ordercount |
+------+--------+------------+
|    5 |   3459 |          1 |
|    4 |    234 |          2 |
|    3 |    693 |          1 |
|    2 |   3432 |          1 |
|    1 |    388 |          3 |
+------+--------+------------+
5 rows in set (0.00 sec)

1
Zum späteren Nachschlagen: Wenn Sie von Rang 1 bis Rang 5 ORDER BY rank ASCbestellen möchten, verwenden Sie (Reihenfolge nach Rang in aufsteigender Reihenfolge). Ich denke, das ist es, was du meinst, aber nicht richtig bestellt
BlueCacti

Antworten:


179

Schauen Sie sich auf diese .

Ändern Sie Ihre Abfrage in:

SET @rank=0;
SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
  FROM orders
  GROUP BY itemID
  ORDER BY ordercount DESC;
SELECT @rank;

Die letzte Auswahl ist Ihre Anzahl.


1
Das fügt den Rang der Ergebnismenge hinzu, bringt sie aber nicht in die richtige Reihenfolge - aktualisierte Frage mit Ergebnissen
George

1
Versuchen Sie, die zu behalten ORDER BY ordercount DESC, und wickeln Sie dann die gesamte Abfrage in eine andere ein, SELECTdie alles von der ersten abruft, aber nach der Rangspalte ordnet (in diesem Fall 0).
Mike Cialowicz

1
Können Sie ein Beispiel dafür zeigen? Wie würde ich die Auswahl einwickeln?
George

9
Schauen Sie sich die Antwort von Swamibebop an
thaddeusmt

1
@ MikeCialowicz, das funktioniert nicht . Die richtige Antwort finden Sie in meiner Lösung oder in der Lösung von Swamibebop.
Pacerier

178
SELECT @rn:=@rn+1 AS rank, itemID, ordercount
FROM (
  SELECT itemID, COUNT(*) AS ordercount
  FROM orders
  GROUP BY itemID
  ORDER BY ordercount DESC
) t1, (SELECT @rn:=0) t2;

1
Vielen Dank für die Klarstellung, dies hat das Problem gelöst, das ich hatte.
thaddeusmt

1
Danke, das war wirklich nützlich für mich :) Ich bin überrascht, dass es keinen einfacheren Weg gibt, Zeilenindizes aus einer Ergebnismenge zu erhalten ... aber trotzdem war dies praktisch.
Ratte

Sie können eine vierte Zeile mit einer inkrementellen Gesamtanzahl hinzufügen, indem Sie die erste select-Anweisung in SELECT \ @rn: = \ @ rn + 1 AS-Rang, Artikel-ID, Auftragsanzahl, \ @tot: = \ @ tot + Auftragsanzahl als Gesamtanzahl ändern. Um den Anfangswert von \ @tot zu definieren, sollte dieser nach t2 hinzugefügt werden: (SELECT \ @tot: = 0) t3. Löschen Sie das \ vor jedem \ @, das ich verwenden musste, um die Mini-Markdown-Formatierung zu umgehen.
Jan Ehrhardt

2
Kann jemand die Relevanz von t1und erklären t2?
Jared

2
@Jared, die MySQL-Syntax braucht nur etwas, um da zu sein. Es kann alles sein, auch xund y.
Pacerier

31

Die Lösung von Swamibebop funktioniert, aber wenn table.*wir die Syntax nutzen, können wir vermeiden, die Spaltennamen des Inneren zu wiederholen,select und ein einfacheres / kürzeres Ergebnis erzielen :

SELECT @r := @r+1 , 
       z.* 
FROM(/* your original select statement goes in here */)z, 
(SELECT @r:=0)y;

Das gibt Ihnen also:

SELECT @r := @r+1 , 
       z.* 
FROM(
     SELECT itemID, 
     count(*) AS ordercount
     FROM orders
     GROUP BY itemID
     ORDER BY ordercount DESC
    )z,
    (SELECT @r:=0)y;

Wissen Sie zufällig, warum die Verwendung @r := @r + 1in einer select-Anweisung funktioniert, aber wenn es sich um eine gespeicherte Prozedur mit handelt declare r int; set r = 0;, beschwert es sich (on r := r +1)?
Dan M.

@Pacerier, ist auch die Reihenfolge der Zeilen, die die zweite Auswahl auswählt, irgendwo garantiert? Ich weiß, dass die Reihenfolge der Zeilen, die von der select ohne order by-Klausel zurückgegeben werden, nirgendwo garantiert ist, und die äußerste Auswahl ist genau das, obwohl sie aus der inneren geordneten Auswahl ausgewählt wird, sodass dies möglicherweise eine Ausnahme darstellt. Wenn dies nicht der Fall ist, kann ich nicht erkennen, wie dies eine korrekte Lösung ist, da es den gleichen Fehler wie Chibus Mikes aufweist - keine Garantie, in welcher Reihenfolge die Auswahl die Datensätze durchläuft und sie nummeriert.
Dan M.

Haben Sie eine Idee, warum ORDER BY nicht funktioniert, wenn es nicht in der Feldliste enthalten ist? Siehe mein Ergebnis: hastebin.com/aluqefunoy.rb
Winter

11

Sie können dazu MySQL-Variablen verwenden. So etwas sollte funktionieren (es besteht jedoch aus zwei Abfragen).

SELECT 0 INTO @x;

SELECT itemID, 
       COUNT(*) AS ordercount, 
       (@x:=@x+1) AS rownumber 
FROM orders 
GROUP BY itemID 
ORDER BY ordercount DESC; 

2
Vorsicht, dies würde nicht funktionieren, da order bydies geschieht, nachdem die Variable @xausgewertet wurde. Versuchen Sie zu experimentieren, indem Sie anhand der anderen Spalten bestellen. Experimentieren Sie auch mit beiden descund asc. Sie werden sehen, dass sie oft versagen und das einzige Mal, wenn es funktioniert, ist es reines Glück , dass die Reihenfolge Ihrer ursprünglichen "Auswahl" dieselbe Reihenfolge hat wie die Reihenfolge von order by. Siehe meine Lösung und / oder Swamibebops Lösung.
Pacerier

@ Pacerier bist du dir da sicher? Ich habe ähnliche Abfragen in einem anderen Beispiel müde gemacht (im Grunde genommen aus der Zahlenspalte auswählen und sie entsprechend ihrer Reihenfolge nummerieren), als ich die Reihenfolge der resultierenden Zeilen änderte, wenn ich nach var / row num ordnete. aber jede Nummer hatte die gleiche Zeilennummer. Wenn ich jedoch nach der Zahlenspalte ordne, ändert das ASC/ DESCdie Reihenfolge, in der diese Zahlen nummeriert wurden (vom kleinsten zum größten oder umgekehrt). Es sieht also so aus, als ob in diesem Fall order byzuerst bewertet wurde.
Dan M.

1

Es ist jetzt in MySQL 8.0 und MariaDB 10.2 integriert:

SELECT
  itemID, COUNT(*) as ordercount,
  ROW_NUMBER OVER (PARTITION BY itemID ORDER BY rank DESC) as rank
FROM orders
GROUP BY itemID ORDER BY rank DESC
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.