mysql row number implementation that is always inc

2019-07-21 03:09发布

My previous search results (containing MySQL - row number in recordset? that really helped me) was not satisfying because sorting by other columns overrides the native sort of @RowNumber.

Consider my simplified member table below:

row_number | id | firstname | lastname
--------------------------------------
1          | 1  | Steve     | Jobs
2          | 2  | Bill      | Gates
3          | 3  | Rasmus    | Lerdorf
4          | 4  | Linus     | Torvalds

resulted by the following query:

SELECT id, firstname, lastname, @RowNumber = @RowNumber + 1 AS row_number
FROM member, (SELECT @RowNumber := 0) AS counter_table

But when I'm going to sort based on some columns other than row_number or id, the row_number's sort will corrupt:

SELECT id, firstname, lastname, @RowNumber = @RowNumber + 1 AS row_number
FROM member, (SELECT @RowNumber := 0) AS counter_table
ORDER BY firstname DESC

Result:

row_number | id | firstname | lastname
--------------------------------------
2          | 2  | Bill      | Gates
4          | 4  | Linus     | Torvalds
3          | 3  | Rasmus    | Lerdorf
1          | 1  | Steve     | Jobs

Note: None of the table, queries and any other thing are tested examples. Only the problem itself is in the real world!

I supposed those simple situations to be easy to understand and resolve. (If they were any problem, please forget about those little mistakes and consider the important problem itself)

2条回答
在下西门庆
2楼-- · 2019-07-21 03:21

That should be obvious: number rows first, order them later.

SELECT * FROM (
  SELECT id, firstname, lastname, @RowNumber = @RowNumber + 1 AS row_number
  FROM member, (SELECT @RowNumber := 0) AS counter_table
) AS sq
ORDER BY firstname DESC

oh wait... you actually want the other way round, order first, number later:

SELECT sq.*, @RowNumber = @RowNumber + 1 AS row_number FROM (
  SELECT id, firstname, lastname
  FROM member
  ORDER BY firstname DESC
) AS sq
CROSS JOIN (SELECT @RowNumber := 0) AS counter_table
查看更多
Ridiculous、
3楼-- · 2019-07-21 03:23

Your implementation on row_number is dependent of the results being returned from the database already in the order in which you are displaying them.

The reason that it fails when you order by firstname is because the results are being returned from the database in order of the primary key, so id 1 get row_number 1, then they're ordered via firstname later (via filesort).

If you add an index on the firstname column, then the results will be fetched from the database ordered by firstname instead of the primary key, so the row numbers will be fine.

If you do an EXPLAIN on your query you will notice that it's probably using the primary key as the index, and using filesort to order the results because it doesn't have an index on firstname. The order occurs after the results are fetched from the table.

Adding an index on firstname, you'll see that it will use the index on firstname to fetch the results from the database already ordered by firstname, so the first name will have row_number 1.

To play it safe, you'll probably want to force the index.

However, this is strictly academic to explain what's occurring and how you might work around the issue.

The most likely solution would be to perform your first query as a subquery, and add the row number in an outer query, after the results have already been ordered. Some applications will reissue a query any time the user wants to change the sort order, however, some applications will cache the results, order them in the application, and generate the row numbers in the application.

查看更多
登录 后发表回答