Як з MySQL можна генерувати стовпчик, що містить індекс запису в таблиці?


100

Чи є спосіб отримати фактичний номер рядка із запиту?

Я хочу мати можливість замовити таблицю під назвою league_girl у полі під назвою оцінка; і повернути ім'я користувача та фактичне положення рядка цього імені користувача.

Я хочу класифікувати користувачів, щоб я міг сказати, де конкретний користувач, тобто. Джо - позиція 100 з 200, тобто

User Score Row
Joe  100    1
Bob  50     2
Bill 10     3

Я бачив кілька рішень тут, але я спробував більшість з них, і жодне з них насправді не повертає номер рядка.

Я спробував це:

SELECT position, username, score
FROM (SELECT @row := @row + 1 AS position, username, score 
       FROM league_girl GROUP BY username ORDER BY score DESC) 

Як похідне

... але це, здається, не повертає позицію рядка.

Якісь ідеї?


це ім'я для рядка, або ви хочете замовити за первинним ключем?
Сарфраз

У SQL номери рядків насправді не важливі. Що ви повинні зробити, це додати первинний ключ автоматичного збільшення до вашого столу.
simendsjo

9
Первинний ключ НІКОЛИ не повинен визначати ідентифікатор рядка, оскільки він не є надійним для фактичної позиції рядка.
TheBounder

3
Крім того, оскільки номер рядка буде функцією показника, який, я вважаю, не є статичним значенням, перетворення його на автоматичне збільшення значення (первинний ключ чи ні) не дасть наміченого результату.
kasperjj

ви можете зберегти потворне для користувацької функції, див. datamakessense.com/mysql-rownum-row-number-function
AdrianBR

Відповіді:


174

Ви можете спробувати наступне:

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r;

JOIN (SELECT @curRow := 0)Частина дозволяє ініціалізацію змінної , не вимагаючи окрему SETкоманду.

Тестовий випадок:

CREATE TABLE league_girl (position int, username varchar(10), score int);
INSERT INTO league_girl VALUES (1, 'a', 10);
INSERT INTO league_girl VALUES (2, 'b', 25);
INSERT INTO league_girl VALUES (3, 'c', 75);
INSERT INTO league_girl VALUES (4, 'd', 25);
INSERT INTO league_girl VALUES (5, 'e', 55);
INSERT INTO league_girl VALUES (6, 'f', 80);
INSERT INTO league_girl VALUES (7, 'g', 15);

Тестовий запит:

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r
WHERE   l.score > 50;

Результат:

+----------+----------+-------+------------+
| position | username | score | row_number |
+----------+----------+-------+------------+
|        3 | c        |    75 |          1 |
|        5 | e        |    55 |          2 |
|        6 | f        |    80 |          3 |
+----------+----------+-------+------------+
3 rows in set (0.00 sec)

19
Крім того, можна форматувати @curRow, замінивши JOINзаяву з коми, наприклад:FROM league_girl l, (SELECT @curRow := 0) r
Майк

2
@Mike: Це правда. І це, мабуть, акуратніше. Дякуємо, що поділилися цією порадою.
Даніель Вассалло

2
@smhnaji MySQL вимагає, щоб кожній "похідній таблиці" було дано ім'я. Я вирішив назвати це "r" :) ... У цьому випадку це мало призначення, але ви зазвичай використовуєте його для посилання на атрибути похідної таблиці, ніби це справжня таблиця.
Даніель Вассалло

20
Люди повинні знати, що цей номер рядка обчислюється до того, як відбудеться будь-яке замовлення, тому цифри можуть збільшитися, якщо в порядку зміниться порядок рядків.
Похмурий ...

7
Чи існує спосіб обчислити цей рядок після ORDER BY?
П'єр де ЛЕСПІНАЙ

38
SELECT @i:=@i+1 AS iterator, t.*
FROM tablename t,(SELECT @i:=0) foo

чи можна це зробити так, щоб стовпчик ітератора був цілим числом, а не десятковим?
kraftydevil

7

Ось структура шаблону, який я використовував:

  select
          /*this is a row number counter*/
          ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
          as rownumber,
          d3.*
  from 
  ( select d1.* from table_name d1 ) d3

І ось мій робочий код:

select     
           ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
           as rownumber,
           d3.*
from
(   select     year( d1.date ), month( d1.date ), count( d1.id )
    from       maindatabase d1
    where      ( ( d1.date >= '2013-01-01' ) and ( d1.date <= '2014-12-31' ) )
    group by   YEAR( d1.date ), MONTH( d1.date ) ) d3

ідеально, такі твори, як шарм і шаблон, можуть бути повторно використані із запитом як параметр ..
Zavael

Це рішення також працює, якщо ваш базовий запит використовує GROUP BY
Дейв R

4

Ви також можете використовувати

SELECT @curRow := ifnull(@curRow,0) + 1 Row, ...

ініціалізувати змінну лічильника.


3
@curRowможе мати значення з останнього разу, коли ви виконували цей запит у поточному сеансі.
Білл Карвін

Правда, але лише у тому випадку, якщо ви повторно запитуєте в одному і тому ж екземплярі з'єднання. Локальні змінні автоматично розміщуються після закриття з'єднання.
Hearth

Так, це я мав на увазі, коли сказав "на поточній сесії".
Білл Карвін

3

Припустимо, що MySQL підтримує його, ви можете легко зробити це за допомогою стандартного підзапросу SQL:

select 
    (count(*) from league_girl l1 where l2.score > l1.score and l1.id <> l2.id) as position,
    username,
    score
from league_girl l2
order by score;

Для великої кількості відображених результатів це буде трохи повільно, і ви хочете замість цього перейти на самостійне з'єднання.


3

Якщо ви просто хочете дізнатися позицію одного конкретного користувача після замовлення за результатами поля, ви можете просто вибрати весь рядок із таблиці, де показник поля вищий за поточний бал користувача. І скористайтеся номером рядка, поверненим + 1, щоб дізнатися, на якій позиції знаходиться даний поточний користувач.

Якщо припустити, що ваша таблиця є league_girlі ваше основне поле id, ви можете скористатися цим:

SELECT count(id) + 1 as rank from league_girl where score > <your_user_score>

0

Я вважав оригінальну відповідь неймовірно корисною, але я також хотів схопити певний набір рядків на основі номерів рядків, які я вставляв. Як такий, я загорнув всю оригінальну відповідь у підзапит, щоб я міг посилатися на номер рядка, який я вставляв.

SELECT * FROM 
( 
    SELECT *, @curRow := @curRow + 1 AS "row_number"
    FROM db.tableName, (SELECT @curRow := 0) r
) as temp
WHERE temp.row_number BETWEEN 1 and 10;

Надіслати запит у підзапиті не дуже ефективно, тому варто перевірити, чи отримаєте ви кращий результат, якщо ваш SQL-сервер обробляє цей запит, чи отримує всю таблицю та змушує програму / веб-сервер маніпулювати рядками після факту .

Особисто мій сервер SQL не надто зайнятий, тому переважніше його обробляти вкладені підзапити.


0

Я знаю, що ОП просить mysqlвідповіді, але оскільки я знайшов, що інші відповіді не працюють для мене,

  • Більшість з них не вдається order by
  • Або вони просто дуже неефективні і роблять ваш запит дуже повільним для жирового столу

Отже, щоб заощадити час для таких, як я, просто індексуйте рядки після отримання їх із бази даних

приклад в PHP:

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1;
}

приклад в PHP, використовуючи зміщення та обмеження для підкачки:

$limit = 20; //page size
$offset = 3; //page number

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1+($limit*($offset-1));
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.