MySQL - Отримайте номер рядка у виборі


181

Чи можу я запустити оператор select і отримати номер рядка, якщо елементи відсортовані?

У мене така таблиця:

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

Потім я можу запустити цей запит, щоб отримати кількість замовлень за ідентифікатором:

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

Це дає мені кількість кожного itemIDз таблиць:

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

Я також хочу отримати номер рядка, тому я міг би сказати, що itemID=388це перший рядок, 234другий і т. Д. (По суті, це рейтинг замовлень, а не лише необроблений підрахунок). Я знаю, що можу це зробити на Java, коли повертаю набір результатів, але мені було цікаво, чи є спосіб обробляти це чисто в SQL.

Оновлення

Встановлення рангу додає його до набору результатів, але не впорядковано належним чином:

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
Для подальшої довідки: Якщо ви хочете замовити з 1-го до 5-го рангу, скористайтеся ORDER BY rank ASC(упорядкуванням за рангом у порядку ASCending). Я здогадуюсь, що це ви маєте на увазі, але не впорядковано належним чином
BlueCacti

Відповіді:


179

Погляньте на це .

Змініть запит на:

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

Останній вибір - це ваш рахунок.


1
Це додає ранг до набору результатів, але не приводить їх у належний порядок - оновлене запитання з результатами
Джордж

1
Спробуйте зберегти ORDER BY ordercount DESC, а потім оберніть увесь запит в інший, SELECTякий отримує все від першого, але замовлення стовпчастої колонки (0 у цьому випадку).
Майк Чаловіч

1
Чи можете ви показати приклад цього? Як би я обернув вибрані?
Джордж

9
Ознайомтеся з відповіддю
swamibebop

1
@MikeCialowicz, це не працює . Щоб отримати правильну відповідь, зверніться до мого рішення чи рішення 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
Дякую за уточнення, це вирішило проблему, яка була поза замовленням у мене.
thaddeusmt

1
Дякую, це було дуже корисно для мене :) Я здивований, що немає більш простого способу отримання "індексів" рядків з набору результатів ... але все одно спасибі це було зручно.
щур

Ви можете додати четвертий рядок із додатковою сумарною кількістю, змінивши перше оператор вибору у SELECT \ @ rn: = \ @ rn + 1 AS rank, itemID, order order, \ @tot: = \ @ tot + order order як totalcount. Для визначення початкового значення \ @tot це слід додати після t2: (SELECT \ @tot: = 0) t3. Видаліть \ до кожного \ @, який мені довелося використовувати, щоб обійти формати міні-відмітки.
Ян Ерхардт

2
Хтось може пояснити актуальність t1і t2?
Джаред

2
@Jared, синтаксису MySQL просто потрібно щось там бути. Це може бути що завгодно, навіть xі y.
Pacerier

31

Рішення Swamibebop працює, але, скориставшись table.*синтаксисом, ми можемо уникнути повторення імен стовпців внутрішніх selectта отримати більш простий / коротший результат:

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

Отже, це дасть вам:

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;

Чи випадково ви знаєте, чому використання @r := @r + 1у вибраному операторі працює, але якщо він знаходиться у збереженій процедурі declare r int; set r = 0;, він скаржиться (увімкнено r := r +1)?
Дан М.

@Pacerier, чи порядок рядків другий вибір десь гарантований? Я знаю, що порядок рядків, повернутих вибором без порядку за допомогою пункту, ніде не гарантується, а самий зовнішній вибір - це саме той, хоча він вибирається із внутрішнього упорядкованого вибору, тож це може бути винятком. Якщо це не так, я не можу зрозуміти, наскільки це правильне рішення, оскільки воно матиме такий самий недолік, як Майк Чібу - немає гарантії, в якому порядку вибору буде проходити записи та нумерувати їх.
Дан М.

Чи маєте ви уявлення, чому ЗАМОВЛЕННЯ НЕ працює, коли його немає у списку полів? Дивіться мій результат: hastebin.com/aluqefunoy.rb
Зима

11

Для цього можна використовувати змінні MySQL. Щось подібне повинно працювати (хоча, воно складається з двох запитів).

SELECT 0 INTO @x;

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

2
Обережно, це не буде працювати, оскільки order byце відбувається після того, як змінна @xбула оцінена. Спробуйте експериментувати, замовивши інші стовпці. Також експериментуйте і з descі asc. Ви побачите, що багато разів вони виходять з ладу і єдиний час, коли це працює, це з чистої долі через те, що ваш вихідний "select" має такий самий порядок, як і порядок order by. Дивіться моє рішення та / або рішення Swamibebop.
Pacerier

@Pacerier Ви впевнені в цьому? Я втомився подібного запиту в іншому прикладі (в основному вибирайте зі стовпця чисел і пронумеруйте їх відповідно до їх порядку), коли мені здалося, що якщо я замовляю за номером var / рядок, коли він змінює порядок отриманих рядків, але кожне число мало однаковий номер рядка Але якщо я впорядкую по стовпцю цифр, то ASC/ DESCзмінив би порядок, в якому ці числа були пронумеровані (від найменших до найбільших або навпаки). Так виглядає, що в цьому випадку order byоцінювали спочатку.
Дан М.

1

Тепер він вбудований в MySQL 8.0 та 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.