SQL Server - 没有Order By子句的分页

时间:2017-03-14 10:24:42

标签: sql sql-server pagination

我的情况是,一个不可预测的SQL语句被赋予程序,我需要在它上面进行分页。最终的SQL语句类似于以下语句:

SELECT * FROM (*Given SQL Statement*) b OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY;

这里的问题是* Given SQL Statement“是不可预测的。它可能包含也可能不包含order by子句。我无法更改此SQL语句的查询结果,我需要对其进行分页。< / p>

我在互联网上搜索了解决方案,但他们都建议按顺序使用任意列,如主键。但它会改变原来的顺序。

5 个答案:

答案 0 :(得分:2)

简短的回答是它无法完成,或者至少无法正常完成。

问题是SQL Server(或任何RDBMS)不能并且不能保证从没有order by子句的查询返回的记录的顺序。
这意味着您无法在此类查询中使用分页 此外,如果对结果集中多次出现的列使用order by子句,则仍无法保证结果集的顺序在所述列的值组中 - 快速示例:

;WITH cte (a, b)
AS
(
    SELECT 1, 'a'
    UNION ALL
    SELECT 1, 'b'
    UNION ALL
    SELECT 2, 'a'
    UNION ALL
    SELECT 2, 'b'
)

SELECT *
FROM cte 
ORDER BY a

两个结果集都是有效的,您无法事先知道会得到什么:

a   b
-----
1   b
1   a
2   b
2   a

a   b
-----
1   a
1   b
2   a
2   b

(当然,你可能会得到其他种类)

答案 1 :(得分:1)

  

这里的问题是* Given SQL Statement“是不可预测的。它可能包含也可能不包含order by子句。

你的内部查询(不可预知的sql语句)不应该包含order by,即使它包含,也不能保证顺序。

要获得有保障的订单,您必须按某些列进行订购。为了使结果具有确定性,有序列/列应该是唯一的

答案 2 :(得分:0)

请注意:我要提出的建议可能非常低效,应该只是用来帮助您回到项目负责人那里,并告诉他们不应该对无序查询进行分页。说完了......

根据您的评论,您说您可以在执行之前更改SQL语句。

您可以将原始查询的结果写入临时表,添加行计数字段以用于后续的分页排序。

因此保留了任何原始排序,您现在可以进行分页。

但当然,首先需要分页的原因是避免向客户端应用程序发送大量数据。虽然这确实可以防止这种情况,但您仍然会将数据复制到临时表,根据行的大小和计数,这可能会非常慢。

您还遇到了一个问题,即页面大小来自客户端,是SQL语句的一部分。解析声明来解决这个问题可能很棘手。

答案 3 :(得分:0)

其他无论如何都使用通知而不使用排序查询都将是不安全的,但是如您所知并对其进行搜索,我可以建议使用这样的查询(但不建议这样做)

;with cte as (
    select *,
        row_number() over (order by (select 0)) rn
    from (
        -- Your query
        ) t
)
select *
from cte
where rn between (@pageNumber-1)*@pageSize+1 and @pageNumber*@pageSize

[SQL Fiddle Demo]

答案 4 :(得分:0)

我终于找到了一种简单的方法,无需在特定列上进行任何排序:

declare @start AS INTEGER = 1, @count AS INTEGER = 5; 

select * from (SELECT *,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS fakeCounter 
FROM (select * from mytable) AS t) AS t2 order by fakeCounter OFFSET @start ROWS 
FETCH NEXT @count ROWS ONLY

mytable中的select *可以是任何查询