相当于LIMIT for DB2


91

你好吗 LIMIT在DB2 for iSeries的?

我有一个包含超过50,000条记录的表,并且我想返回记录0到10,000,以及记录10,000到20,000。

我知道在SQL中,您LIMIT 0,10000在查询末尾写0到10,000,并LIMIT 10000,10000在查询末尾写 10000到20,000

那么,如何在DB2中完成呢?什么是代码和语法?(赞赏完整的查询示例)


ROW_NUMBER()仅在iSeries DB2 V5R4中实现。对于以前的版本,请尝试使用类似的RRN()。
保罗·摩根

RRN()与row_number()完全不同。
布兰登·彼得森

没有为我工作。Sytanx错误。
elcool 2010年

1
尝试使用RRN(filename),它将给出该行的物理相对记录号。RRN不会是连续的,如果行已删除,则可以跳过数字。RRN也不会按键顺序排列,但是如果没有发生删除,则RRN将根据添加顺序排列。在任何情况下,RRN在一行中都是唯一的,可用于选择表的子集。
保罗·摩根

Answers:


139

使用FETCH FIRST [n] ROWS ONLY

http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.perf/db2z_fetchfirstnrows.htm

SELECT LASTNAME, FIRSTNAME, EMPNO, SALARY
  FROM EMP
  ORDER BY SALARY DESC
  FETCH FIRST 20 ROWS ONLY;

要获得范围,您必须使用ROW_NUMBER()(自v5r4起)并在WHERE子句中使用它:(从此处窃取:http : //www.justskins.com/forums/db2-select-how-to-123209.html )

SELECT code, name, address
FROM ( 
  SELECT row_number() OVER ( ORDER BY code ) AS rid, code, name, address
  FROM contacts
  WHERE name LIKE '%Bob%' 
  ) AS t
WHERE t.rid BETWEEN 20 AND 25;

是的,我也找到了,呵呵 我正在同时编辑问题,以表明我也想要中间行。
elcool 2010年

2
您必须使用ROW_NUMBER做类似的事情:justskins.com/forums/db2-select-how-to-123209.html

ROW_NUMBER不是有效的关键字。但是对于链接,它给了我一个主意,并且有效。
elcool 2010年

13

开发了这种方法:

您需要一个表,该表具有可以排序的唯一值。

如果您希望行10,000到25,000,并且表有40,000行,则首先需要获取起点和总行数:

int start = 40000 - 10000;

int total = 25000 - 10000;

然后将这些通过代码传递给查询:

SELECT * FROM 
(SELECT * FROM schema.mytable 
ORDER BY userId DESC fetch first {start} rows only ) AS mini 
ORDER BY mini.userId ASC fetch first {total} rows only

请注意,从结果集中排除了第10000行,第一行是第10001行。
蓝色2012年

1
有趣的解决方案。我打算使用它来与H2测试数据库兼容...但是,可悲的是,它的工作速度比SELECT row_number()OVER(按代码排序)方法慢30倍。
manuna

9

DB2 for i 7.1和7.2最近增加了对OFFSET和LIMIT的支持。您需要以下DB PTF组级别才能获得此支持:

  • SF99702 9级(适用于IBM i 7.2)
  • SF99701 38级(适用于IBM i 7.1)

请参阅此处以获取更多信息:OFFSET和LIMIT 文档,DB2 for i增强维基


7

这是我想出的解决方案:

select FIELD from TABLE where FIELD > LASTVAL order by FIELD fetch first N rows only;

通过将LASTVAL初始化为0(或对于文本字段为”),然后将其设置为最新记录集中的最后一个值,这将以N条记录的块形式逐步遍历表。


(我最初以为您是在表中设置值,这在并发系统上会出现很大问题)是的,这在您顺序读取表的情况下应该可以使用,尽管您需要某种方式打破平局列N(小于列中相同值的数目)(尽管也是如此ROW_NUMBER())。还必须谨慎选择初始值- 0如果该列包含负值,显然会出现问题。需要注意的是空值。如果页面被跳过,将无法工作。
Clockwork-Muse 2014年

感谢您的评论。我认为有一个隐含的假设,即我们用来控制查询的字段是唯一的并且单调递增。我同意,如果这些假设不成立,则无法访问表中的所有记录。而且,当然,您是正确的,您必须从有意义的LASTVAL开始。总的来说,我认为您想从“从TABLE中选择MINIMUM(FIELD)”返回的内容开始。如果对该字段建立了索引,则大多数数据库引擎将比顺序读取整个表更好。
汤姆·巴伦

2

@elcool的解决方案是一个聪明的主意,但是您需要知道总行数(在执行查询时,它甚至可能会改变!)。因此,我提出了一个修改后的版本,不幸的是,它需要3个子查询,而不是2个:

select * from (
    select * from (
        select * from MYLIB.MYTABLE
        order by MYID asc 
        fetch first {last} rows only 
        ) I 
    order by MYID desc
    fetch first {length} rows only
    ) II
order by MYID asc

{last}应该用我需要的最后一条记录的行数代替,应该用我需要的行数{length}代替,计算为last row - first row + 1

例如,如果我希望从10到25的行(总共16行),{last}将为25,并且{length}将为25-10 + 1 = 16。


当别人花时间回答他们的问题时,我鄙视那些投反对票的人。
jp2code

1

您还应该考虑OPTIMIZE FOR n ROWS子句。有关限制所有SELECT语句准则主题中的DB2 LUW文档,所有这些的更多详细信息:

  • OPTIMIZE FOR子句声明旨在仅检索结果的子集,或优先于仅检索前几行。然后,优化器可以选择访问计划,以最小化用于检索前几行的响应时间。

1

试试这个

SELECT * FROM
    (
        SELECT T.*, ROW_NUMBER() OVER() R FROM TABLE T
    )
    WHERE R BETWEEN 10000 AND 20000

0

有两种解决方案可以在DB2表上有效地分页:

1-使用函数row_number()和已在另一篇文章中介绍的OVER子句的技术(“ SELECT row_number()OVER(ORDER BY ...)”)。在一些大桌子上,我注意到有时性能会下降。

2-使用可滚动光标的技术。实现取决于所使用的语言。在大表上,该技术似乎更可靠。

我在明年的研讨会上介绍了用PHP实现的2种技术。可以在此链接上找到幻灯片: http //gregphplab.com/serendipity/uploads/slides/DB2_PHP_Best_practices.pdf

抱歉,该文档仅以法语提供。


0

有以下可用选项:-

DB2 has several strategies to cope with this problem.
You can use the "scrollable cursor" in feature.
In this case you can open a cursor and, instead of re-issuing a query you can FETCH forward and backward.
This works great if your application can hold state since it doesn't require DB2 to rerun the query every time.
You can use the ROW_NUMBER() OLAP function to number rows and then return the subset you want.
This is ANSI SQL 
You can use the ROWNUM pseudo columns which does the same as ROW_NUMBER() but is suitable if you have Oracle skills.
You can use LIMIT and OFFSET if you are more leaning to a mySQL or PostgreSQL dialect.  
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.