重写查询以进行分页
Posted
技术标签:
【中文标题】重写查询以进行分页【英文标题】:rewrite a query to have pagination 【发布时间】:2017-03-03 05:10:03 【问题描述】:我有一个程序,其中用户提供了一个可以在数据库上执行的 sql 查询(要运行的数据库的详细信息也由用户提供)。此查询在数据库上执行,稍后处理结果。
一项新功能要求以分页方式执行查询,即如果用户的查询将正常返回 20 条记录,并且用户提供的页面大小为 5,则查询应执行 4 次,每次检索 5 条记录时间。
我可以为没有 CTE 的选择查询执行此操作,但我不确定如何处理包含 CTE 的一般查询。
我将 CTE 的查询修改如下:
public static String rewrite(String sql)
return "select * from ("
+ "select (row_number() over ()) as generated_row_number, t.* "
+ "from ("
+ sql
+ ") as t"
+ ") "
+ "where generated_row_number < ?"
+ " and generated_row_number >= ?";
起始索引和页面大小稍后作为参数添加。
我将如何处理包含 CTE 的查询的类似功能?
可以假设数据库是 DB2,但最好使用通用解决方案。
连接到数据库的用户也没有创建视图的权限。
【问题讨论】:
使用偏移量怎么样? "order by 1 offset 10((page number - 1) * pagesize) ROWS fetch NEXT 5(your page size) ROWS ONLY" 【参考方案1】:在 SQL 中查询的一种方便方法是使用偏移提取。我经常用它来分页。
Select StockCode,Description,Quantity from Inventory order by StockCode offset 0 ROWS fetch NEXT 5 ROWS ONLY
所以在代码中它会是这样的
public static string(int Page, int PerPage)
return "Select StockCode,Description,Quantity from Inventory order by StockCode offset " + ((Page - 1) * PerPage).ToString() + " ROWS fetch NEXT " + PerPage.ToString() + " ROWS ONLY"
如果您需要更通用的解决方案,您可以尝试嵌套选择:
public static String rewrite(String sql, int Page, int PerPage)
return "Select * from (" + sql + ") order by 1 offset " + ((Page - 1) * PerPage).ToString() + " ROWS fetch NEXT " + PerPage.ToString() + " ROWS ONLY"
【讨论】:
我得到以下错误,使用这个:select * from test offset 20 rows fetch next 20 rows only
An unexpected token "from test" was found following "select * ". Expected tokens may include: "<space>".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.13.127
你需要有“order by”
还是不行:select * from test order by 1 offset 20 rows fetch next 20 rows only An unexpected token "offset 20 rows fetch next 20 rows only" was found following "m test order by 1 ". Expected tokens may include: "<space>".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.13.127
你运行的是什么版本的sql?
在本例中,服务器是 DB2 express c 10.5。【参考方案2】:
试试这个:
public static String rewrite(String sql)
return "with tmptable as (" + sql + ")"
+ " select * from ("
+ " select row_number() over () as generated_row_number, t.* "
+ " from tmptable t
+ ") tmp"
+ " where tmp.generated_row_number < ?"
+ " and tmp.generated_row_number >= ?";
【讨论】:
如果原始查询还包含 WITH 子句,这将不起作用,这是我遇到的问题。它也不适用于一些简单的选择,失败并出现错误 -153以上是关于重写查询以进行分页的主要内容,如果未能解决你的问题,请参考以下文章