我的情况是,一个不可预测的SQL语句被赋予程序,我需要在它上面进行分页。最终的SQL语句类似于以下语句:
SELECT * FROM (*Given SQL Statement*) b OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY;
这里的问题是* Given SQL Statement“是不可预测的。它可能包含也可能不包含order by子句。我无法更改此SQL语句的查询结果,我需要对其进行分页。< / p>
我在互联网上搜索了解决方案,但他们都建议按顺序使用任意列,如主键。但它会改变原来的顺序。
答案 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
答案 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 *可以是任何查询