2010-03-26 10 views
150

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

Mam tabeli tak:

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

mogę następnie uruchomić tę kwerendę, aby uzyskać liczbę zleceń przez ID:

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

To daje mi liczyć każdego itemID w tabela tak:

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

Chcę również uzyskać numer wiersza, więc mogłem stwierdzić, że itemID=388 to pierwszy wiersz, 234 jest drugim, itd. (W zasadzie ranking zamówień, a nie tylko liczba nieprzetworzona). Wiem, że mogę to zrobić w Javie, gdy otrzymam zestaw wyników, ale zastanawiałem się, czy istnieje sposób, aby poradzić sobie z tym wyłącznie w SQL.

Aktualizacja

Ustawianie rangę dodaje go do zestawu wyników, ale nie właściwie uporządkowane:

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

mysql> SELECT @rank:[email protected]+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

Na przyszłość: Jeśli chcesz zamówić od 1 do 5, użyj "ORDER BY rank ASC" (porządkowanie według rangi w porządku ASCending). Domyślam się, że to masz na myśli * ale nie jest prawidłowo uporządkowany * – GroundZero

+0

Prawdopodobny duplikat [ROW \ _NUMBER() w MySQL] (http://stackoverflow.com/questions/1895110/row-number-in-mysql) –

Odpowiedz

147

Spójrz na this.

zmienić zapytanie do:

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

To dodaje rangę do zestawu wyników, ale nie umieszcza 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 "SELECT", które pobiera wszystko od pierwszy, ale zamówienia według kolumny rangi (w tym przypadku 0). –

+1

Czy możesz pokazać przykład tego? Jak zawinąć selekcje? – George

9

można użyć zmiennych mysql to zrobić. Coś takiego powinno zadziałać (chociaż są to dwa zapytania).

SELECT 0 INTO @x; 

SELECT itemID, COUNT(*) as ordercount, (@x:[email protected]+1) as rownumber FROM orders GROUP BY itemID ORDER BY ordercount DESC; 
+0

Ostrożnie, to nie zadziała, ponieważ 'order by' happen ** after ** zmienna' @ x' została oszacowana. Spróbuj eksperymentować, zamawiając używając innych kolumn. Eksperymentuj również z 'desc' i' asc'. Zobaczysz, że wiele razy będą zawiedzione, a jedyne czasy, kiedy to zadziała, to ** szczęście ** ze względu na kolejność twojego oryginalnego "wybierz" o tej samej kolejności, co kolejność "zamawiania". Zobacz moje rozwiązanie i/lub rozwiązanie Swamibebop. – Pacerier

+0

@Pacerier jesteś tego pewien? Zmęczone podobne zapytanie w innym przykładzie (w zasadzie wybierz z kolumny liczb i numeruj je zgodnie z ich kolejnością) wydawało się, że jeśli zamawiam przez var/row num, kiedy zmieniło kolejność wynikowych wierszy, ale każda liczba miała ten sam numer wiersza. Ale jeśli zamówię przez kolumnę z numerem, to "ASC"/"DESC" zmieni kolejność, w której numery te będą ponumerowane (od najmniejszego do największego lub odwrotnie). Wygląda więc, że w tym przypadku najpierw oceniano "zamówienie przez". –

157
SELECT @rn:[email protected]+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; 
+0

Dziękuję za wyjaśnienie, to rozwiązało problem braku porządku, jaki miałem. – thaddeusmt

+1

Dzięki, to było dla mnie bardzo przydatne :) Jestem zaskoczony, że nie ma bardziej prostego sposobu na uzyskanie indeksów wiersza z zestawu wyników ... ale w każdym razie dzięki temu było to przydatne. – rat

+0

Możesz dodać czwarty wiersz z przyrostową kwotą całkowitą, zmieniając pierwszą instrukcję select w SELECT \ @rn: = \ @ rn + 1 AS rank, itemID, ordercount, \ @tot: = \ @ tot + ordercount jako totalcount. Aby zdefiniować wartość początkową \ @tot należy to dodać po t2: (SELECT \ @tot: = 0) t3. Usuń \ przed każdym \ @, którego musiałem użyć, aby ominąć formatowanie Mini-Markdown. –

21

rozwiązanie Swamibebop za roboty, ale wykorzystując table.* składni, możemy avoid repeating nazwy kolumn na wewnętrzny select i uzyskać prostszą/krótszy wynik:

select @r := @r+1 , z.* from(

    /* your original select statement goes in here */ 

)z, (select @r:=0)y; 

Tak 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; 
+0

To działało jak mistrz dla tego, czego potrzebowałem. Dziękuję Ci! – user2020930

+0

Dziękujemy! uruchom to całkiem dobrze! dzięki! –

+0

Czy przypadkiem wiesz, dlaczego używa '@r: = @r + 1' w instrukcji select działa, ale jeśli jest w procedurze przechowywanej z' declare r int; set r = 0; ', narzeka (na' r: = r + 1')? –