【问题标题】:Equivalent of LIMIT for DB2DB2 的 LIMIT 等效项
【发布时间】:2011-04-22 13:28:12
【问题描述】:

您如何在 DB2 for iSeries 中使用LIMIT

我有一个超过 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() 完全不同。
  • 对我不起作用。语法错误。
  • 尝试 RRN(filename) 它将给出行的物理相对记录号。如果行已被删除,RRN 不会是连续的并且可以跳过数字。 RRN 也不会按键顺序排列,但如果没有发生删除,则将基于添加顺序排列。在任何情况下,RRN 对于一行都是唯一的,可用于选择表的子集。
  • DB2 根据programmingzen.com/2010/06/02/…从 DB2 9.7.2 提供限制关键字支持

标签: db2 limit ibm-midrange


【解决方案1】:

使用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;

【讨论】:

  • 是的,我也找到了,呵呵。我同时在编辑问题以表明我也想要中间行。
  • 你必须用 ROW_NUMBER 做这样的事情:justskins.com/forums/db2-select-how-to-123209.html
  • ROW_NUMBER 不是有效的关键字。但是谢谢这个链接,它给了我一个想法并且它有效。
【解决方案2】:

开发了这个方法:

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

如果您想要 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 行。
  • 有趣的解决方案。我打算用它来兼容 H2 测试数据库......但是,遗憾的是,它的工作速度比 SELECT row_number() OVER (ORDER BY code) 方法慢了约 30 倍。
【解决方案3】:

最近在 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 documentation,DB2 for i 增强 Wiki

【讨论】:

    【解决方案4】:

    这是我想出的解决方案:

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

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

    【讨论】:

    • (我最初以为您是在表中设置值,这在并发系统上会壮观出现问题)是的,这应该适用于您正在做的情况顺序读取表格,尽管在 N 小于列中相同值的数量的情况下您需要某种决胜列(尽管在使用 ROW_NUMBER() 时也是如此)。初始值也必须谨慎选择 - 如果列包含 negative 值,0 显然会出现问题。空值需要小心。如果页面跳过,将无法正常工作。
    • 感谢您的评论。我认为有一个隐含的假设,即我们用来控制查询的字段是唯一的并且单调递增。我同意,如果这些假设不成立,则无法访问表中的所有记录。而且,当然,您必须从有意义的 LASTVAL 开始是正确的。一般来说,我认为您希望从“从 TABLE 中选择 MINIMUM(FIELD)”返回的任何内容开始。如果该字段被索引,大多数数据库引擎会比顺序读取整个表做得更好。
    【解决方案5】:

    @elcool's solution 是一个聪明的主意,但您需要知道总行数(甚至可以在执行查询时更改!)。所以我提出了一个修改版本,不幸的是需要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。

    【讨论】:

    • 我鄙视那些在别人花时间回答他们的问题时投反对票的人。
    【解决方案6】:

    试试这个

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

    【讨论】:

      【解决方案7】:

      LIMIT 子句允许您限制查询返回的行数。 LIMIT 子句是 SELECT 语句的扩展,具有以下语法:

      SELECT select_list
      FROM table_name
      ORDER BY sort_expression
      LIMIT n [OFFSET m];
      

      在这种语法中:

      • n 是要返回的行数。
      • m 是在返回 n 行之前要跳过的行数。

      LIMIT 子句的另一个较短版本如下:

      LIMIT m, n;
      

      此语法意味着跳过m 行并从结果集中返回下一个n 行。

      表可能以未指定的顺序存储行。如果您不将ORDER BY 子句与LIMIT 子句一起使用,则返回的行也未指定。因此,最好始终将ORDER BY 子句与LIMIT 子句一起使用。

      更多详情请见Db2 LIMIT

      【讨论】:

        【解决方案8】:

        您还应该考虑 OPTIMIZE FOR n ROWS 子句。在Guidelines for restricting SELECT statements 主题中的 DB2 LUW 文档中了解所有这些的更多详细信息:

        • OPTIMIZE FOR 子句声明了仅检索结果子集或优先检索仅前几行的意图。然后,优化器可以选择能够最大限度缩短检索前几行的响应时间的访问计划。

        【讨论】:

          【解决方案9】:

          有两种解决方案可以有效地对 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

          抱歉,此文档仅提供法语版本。

          【讨论】:

            【解决方案10】:

            有以下可用选项:-

            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.  
            

            【讨论】:

              猜你喜欢
              • 2021-05-09
              • 1970-01-01
              • 2010-10-22
              • 1970-01-01
              • 2013-05-24
              • 1970-01-01
              • 2013-07-23
              • 2012-02-19
              • 1970-01-01
              相关资源
              最近更新 更多