【问题标题】:Select range (limit) of results in Oracle SQL / pagination在 Oracle SQL / 分页中选择结果范围(限制)
【发布时间】:2014-03-28 21:55:49
【问题描述】:

假设我们有下表:

CREATE TABLE "ARTICLE_COUNTER_STATISTICS_M"
(
  "ID"        NUMBER(19,0) NOT NULL ENABLE,
  "ITEMCOUNT" NUMBER(19,0),
  "VERSION" TIMESTAMP (6) DEFAULT SYSTIMESTAMP
)

唯一约束是在 ID 和 VERSION 字段上。

可能在 DB 中的某些行的示例(所有记录的时间戳始终相同):

1374659422641   22  2014.02.26 09:45:01,000000000
1387797258001   7   2014.02.26 09:45:01,000000000
1387796687862   1   2014.02.26 09:45:01,000000000
1387800521317   1   2014.02.26 09:45:01,000000000

现在,如果我们要选择 ID、itemcount 并按 itemcount 排序,我们将执行以下操作:

SELECT id, SUM(itemcount) as count, version 
FROM ARTICLE_COUNTER_STATISTICS_m 
WHERE id != '0' 
GROUP BY id, version 
ORDER BY version DESC, SUM(itemcount) DESC 

但不清楚的是,我们如何选择仅在一定范围内的结果。例如,计数最多的 10 到 20 个项目?我试过这样的事情:

SELECT id, count, version FROM( 
    SELECT id, SUM(itemcount) as count, version 
    FROM ARTICLE_COUNTER_STATISTICS_m 
    WHERE id != '0' 
    GROUP BY id, version 
    ORDER BY version DESC, SUM(itemcount) DESC 
) where rownum >= 0 and rownum <= 20

但如果 "where rownum >= n" 中的 n 大于 1(它只返回空结果),则它不起作用。我知道可能必须使用 ROW_NUMBER() 函数来实现目标,但我无法让它工作。有任何想法吗?谢谢!

【问题讨论】:

  • 与您的问题无关,但使用 "WHERE id != '0'" 会严重损害您的性能 - Oracle 会将 ID 列转换为字符串以进行比较。请改用“WHERE id != 0”(不带引号)。

标签: sql oracle pagination rows


【解决方案1】:

这是一个row_number 示例:

SELECT * 
FROM   (SELECT id, itemcount, version, 
               ROW_NUMBER() OVER (ORDER BY version DESC, itemcount DESC) AS rn
        FROM   (SELECT id, SUM(itemcount) as itemcount, version 
                FROM ARTICLE_COUNTER_STATISTICS_m 
                WHERE id != '0' 
                GROUP BY id, version
               )
        )
WHERE  rn BETWEEN 3 AND 20 -- just an example

请注意,row_number 将任意顺序分配给具有相同属性的项目(根据 window 子句)。因此,例如,如果您的前三个项目都有version=100itemcount=100,而您使用rn BETWEEN 2 AND 4,则不知道哪一个会被排除。为避免这种情况,您可以使用rank,它将相同的值分配给具有相同属性的项目(同样,由 window 子句定义)。

【讨论】:

  • 谢谢,这也有效(第 2 行的计数必须更改为 itemcount,但我无法编辑您的帖子)。但是,如果我用 RANK() 替换 ROW_NUMBER(),例如,它会给我 2 到 5 的错误结果。我还有什么需要修改的才能与排名一起使用吗?
  • 回复:countitemcount - 已修复,感谢您的关注。回复:rank 的错误结果 - 正如我所提到的,具有相同属性的物品将具有相同的价值,所以你可能会得到比你讨价还价的更多/更少的物品(但至少它是确定性的)。你能举一个没有按计划行事的具体例子吗?
  • 没关系,它工作正常。只是当使用 Dba 索引提供的 rownum 示例时,索引从 0 开始,但 ROW_NUMBER() 或 RANK() 从 1 开始。感谢 Mureinik 和 Dba 的精彩回答! :) 我想将两者都标记为已接受的答案,但我必须选择一个:(。我会选择 Mureinik 的,因为我已经放弃了对 Dba 的投票。:)
【解决方案2】:

这样试试,

SELECT * 
FROM(
    SELECT a.*, rownum rn
    FROM(
        SELECT id, SUM(itemcount) as count, version 
        FROM   ARTICLE_COUNTER_STATISTICS_m 
        WHERE  id != 0
        GROUP BY id, version 
        ORDER BY VERSION DESC, SUM(itemcount) DESC
          ) a
    WHERE ROWNUM <= 20
    )
WHERE rn > 0;

【讨论】:

  • 谢谢,这行得通!任何想法我的例子有什么问题,为什么它不起作用?可以用 ROW_NUMBER() 代替吗?
  • @Javatar,是的,你也可以使用ROW_NUMBER() 来获得这个,但是在ORACLE 中效率很低。请参阅以下链接以了解 b/w ROWNUMROW_NUMBER 的区别。 explainextended.com/2009/05/06/oracle-row_number-vs-rownum
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-23
相关资源
最近更新 更多