MySQL - Uzyskaj numer wiersza przy zaznaczeniu

181

Czy mogę uruchomić instrukcję select i uzyskać numer wiersza, jeśli elementy są posortowane?

Mam taki stół:

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

Następnie mogę uruchomić to zapytanie, aby uzyskać liczbę zamówień według identyfikatora:

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

Daje mi to liczbę itemIDw tabeli w następujący sposób:

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

Chcę również uzyskać numer wiersza, więc mógłbym powiedzieć, że itemID=388jest to pierwszy wiersz, 234jest drugi itd. (Zasadniczo ranking zamówień, a nie tylko surowa liczba). Wiem, że mogę to zrobić w Javie, gdy odzyskam wyniki, ale zastanawiałem się, czy istnieje sposób, aby poradzić sobie z tym czysto w języku SQL.

Aktualizacja

Ustawienie rangi dodaje ją do zestawu wyników, ale nie jest odpowiednio uporządkowana:

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)
Jerzy
źródło
1
Do wykorzystania w przyszłości: jeśli chcesz zamówić od rangi 1 do rangi 5, użyj ORDER BY rank ASC(sortuj według rangi w porządku rosnącym). Myślę, że właśnie to masz na myśli, ale nie odpowiednio uporządkowane
BlueCacti
Możliwy duplikat ROW_NUMBER () w MySQL
Ciro Santilli 25 冠状 病 六四 事件 法轮功

Odpowiedzi:

179

Spójrz na to .

Zmień zapytanie na:

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

Ostatni wybór to liczba.

Mike Ciałowicz
źródło
1
To dodaje rangę do zestawu wyników, ale nie ustawia ich we właściwej kolejności - zaktualizowane pytanie z wynikami
George
1
Spróbuj zachować ORDER BY ordercount DESC, a następnie zawiń całe zapytanie w innym, SELECTktóry pobiera wszystko od pierwszego, ale porządkuje według kolumny rangi (w tym przypadku 0).
Mike Cialowicz
1
Czy możesz podać przykład tego? Jak owinąć zaznaczenia?
George
9
Sprawdź odpowiedź
swamibebop
1
@MikeCialowicz, To nie działa . Prawidłową odpowiedź znajdziesz w moim rozwiązaniu lub rozwiązaniu 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;
Swamibebop
źródło
1
Dziękuję za wyjaśnienie, dzięki czemu rozwiązałem problem z zamówieniem, który miałem.
thaddeusmt
1
Dzięki, to było dla mnie bardzo przydatne :) Dziwię się, że nie ma prostszego sposobu na uzyskanie „indeksów” wierszy z zestawu wyników ... ale w każdym razie dzięki to było przydatne.
szczur
Możesz dodać czwarty wiersz z przyrostową liczbą całkowitą, zmieniając pierwszą instrukcję select w SELECT \ @rn: = \ @ rn + 1 pozycja AS, itemID, ordercount, \ @ tot: = \ @ tot + liczba zamówienia jako totalcount. Aby zdefiniować wartość początkową \ @tot, należy ją dodać po t2: (SELECT \ @tot: = 0) t3. Usuń \ przed każdym \ @, którego musiałem użyć, aby obejść formatowanie mini-Markdown.
Jan Ehrhardt
2
Czy ktoś może wyjaśnić znaczenie t1i t2?
Jared
2
@Jared, składnia MySQL po prostu potrzebuje czegoś, aby tam być. Może to być wszystko, nawet xi y.
Pacerier
31

Rozwiązanie Swamibebop działa, ale korzystając ze table.*składni, możemy uniknąć powtarzania nazw wewnętrznych kolumn selecti uzyskać prostszy / krótszy wynik:

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

To da ci:

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;
Pacerier
źródło
Czy przypadkiem wiesz, dlaczego @r := @r + 1działa użycie instrukcji select, ale jeśli jest w procedurze składowanej declare r int; set r = 0;, narzeka (włącza r := r +1)?
Dan M.,
@Pacerier, czy kolejność wierszy jest gdzieś gwarantowana? Wiem, że kolejność wierszy zwracanych przez select bez kolejności przez klauzulę nie jest nigdzie gwarantowana, a skrajnie zewnętrzny select jest dokładnie taki, chociaż wybiera z wewnętrznego sortowania uporządkowanego, więc może to być wyjątek. Jeśli tak nie jest, nie widzę, jak to jest poprawne rozwiązanie, ponieważ będzie miało tę samą wadę co Mike Chibu - nie ma gwarancji, w jakiej kolejności wybierane są zapisy i numerowane je.
Dan M.,
Czy masz pojęcie, dlaczego ORDER BY nie działa, gdy nie ma go na liście pól? Zobacz mój wynik: hastebin.com/aluqefunoy.rb
Winter
11

Możesz użyć do tego zmiennych MySQL. Coś takiego powinno działać (jednak składa się z dwóch zapytań).

SELECT 0 INTO @x;

SELECT itemID, 
       COUNT(*) AS ordercount, 
       (@x:=@x+1) AS rownumber 
FROM orders 
GROUP BY itemID 
ORDER BY ordercount DESC; 
Chibu
źródło
2
Ostrożnie, to nie zadziała, ponieważ order bydzieje się to po@x ocenie zmiennej . Spróbuj eksperymentować, zamawiając za pomocą innych kolumn. Poeksperymentować także z obu desci asc. Przekonasz się, że wiele razy zawiodą, a tylko wtedy, gdy to działa, to przez szczęście, ponieważ kolejność twojego oryginalnego „wyboru” ma taką samą kolejność jak kolejność order by. Zobacz moje rozwiązanie i / lub rozwiązanie Swamibebop.
Pacerier
@Pacerier jesteś tego pewien? Zmęczyłem podobne zapytanie w innym przykładzie (w zasadzie wybieram z kolumny liczb i numeruję je zgodnie z ich kolejnością), wydawało mi się, że jeśli zamówię według var / row num, to po zmianie kolejności wynikowych wierszy, ale każda liczba miała ten sam numer wiersza. Ale jeśli posortuję według kolumny liczb, wtedy ASC/ DESCzmieniłby kolejność, w jakiej te liczby były ponumerowane (od najmniejszej do największej lub odwrotnie). Wygląda na to, że w tym przypadku order byzostał oceniony jako pierwszy.
Dan M.,
1

Jest teraz wbudowany w MySQL 8.0 i MariaDB 10.2:

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
karmel
źródło