Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL ROW_NUMBER and sorting issue

In SQL 2005/2008 database we have table BatchMaster. Columns: RecordId bigint - autoincremental id, BatchNumber bigint - unique non-clustered index, BatchDate). We have sproc that returns paginated data from this table. That sproc works fine for most of the clients, but at one SQL server instance we have problem with records order. In general, at sproc we do

select * from
(
    select row_number() over (order by bm.BatchDate desc, bm.BatchNumber desc) as Row,
    *
    from dbo.BatchMaster bm with (nolock)
)
where Row between @StartingRow and @EndgingRow

So, as you can notice from the script above we want return records sorted by BatchDate and BatchNumber. That's not gonna happen for one of our client: enter image description here

Records are in wrong order. Also, notice first column (Row), it is not in ascending order.

Can someone explain why so?

like image 509
vk_muse Avatar asked Jun 11 '12 13:06

vk_muse


People also ask

Does ROW_NUMBER need ORDER BY?

This example sequentially numbers each row, but does not order them. Because the ROW_NUMBER function requires an ORDER BY clause, the ROW_NUMBER function specifies ORDER BY (SELECT 1) to return the rows in the order in which they are stored in the specified table and sequentially number them, starting from 1.

What results will be returned by a ROW_NUMBER function if there is no ORDER BY clause in the query?

The PARTITION BY clause is optional. If you skip it, the ROW_NUMBER() function will treat the whole result set as a single partition.

How the ROW_NUMBER function can return non deterministic result?

If there are duplicate tuples for the combination of partitioning and order by columns list, then the function can assign the row numbers in any order for such duplicates. This can eventually lead to a non-deterministic result.

Which is faster group by or ROW_NUMBER?

The group by should be faster. The row number has to assign a row to all rows in the table. It does this before filtering out the ones it doesn't want. The second query is, by far, the better construct.


2 Answers

Assuming you want the lowest BatchNumber for a given BatchDate with the smallest Row number and that you want orderer by the Row, try this:

select * from
(
    select row_number() over (order by bm.BatchDate desc, bm.BatchNumber asc) as Row,
    *
    from dbo.BatchMaster bm with (nolock)
)
where Row between @StartingRow and @EndgingRow
order by Row
like image 117
aF. Avatar answered Nov 15 '22 04:11

aF.


Your code doesn't actually sort the results, it only sets 'Row' based on the order of BatchDate and Batchnumber and appears to be doing that correctly. You need to add ORDER BY Row to your statement.

like image 25
MartW Avatar answered Nov 15 '22 06:11

MartW