【问题标题】:Oracle rownum behavior with mod function带有 mod 函数的 Oracle rownum 行为
【发布时间】:2012-08-22 19:14:21
【问题描述】:

给定

CREATE TABLE Foo(v1 integer, v2 integer);

INSERT INTO Foo VALUES (1,2);
INSERT INTO Foo VALUES (3,4);
INSERT INTO Foo VALUES (5,6);

SELECT COUNT(*) FROM Foo WHERE mod(rownum,2) = 0;

返回 0 行,应该返回 1

SELECT COUNT(*) FROM (SELECT mod(rownum,2) z FROM Foo) tt WHERE z=0;

返回 1 行

我在这里缺少什么?我在 ROWNUM 或 MOD 文档中没有看到任何建议。

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    ROWNUM 在您查询之前不会被分配,因此您将无法在类似的WHERE 子句中使用它。

    您可以执行以下操作:

    SELECT COUNT(*) 
    FROM
    (
      select v1, v2, rownum rn
      from Foo 
    ) f
    WHERE mod(rn,2) = 0;
    

    ROWNUM 是该行在结果集中的位置,在选择记录后对其进行评估。

    这些类型的查询永远不会起作用:

    WHERE ROWNUM > x
    WHERE ROWNUM BETWEEN x AND y
    

    但这会起作用

    WHERE ROWNUM < x
    

    由于您想使用mod 函数评估rownum,因此它将无法工作,因为此时rownum 不可用。这就是为什么您必须将它放在子查询中才能使用 mod 函数。

    【讨论】:

      【解决方案2】:

      ROWNUM 返回实际查询的行号,而不是查询所基于的表的行号。所以SELECT COUNT(*) ... 返回一行,行号为 1,mod(rownum,2) != 0,然后被 WHERE 原因丢弃,实际上根本不返回任何行。

      将行号作为列返回的(未过滤的)子选择会有所帮助。然后将 WHERE 子句应用于外部选择。

      【讨论】:

      • 我知道它不是基于基表的,但是这个说法正确吗? - ROWNUM 逐行计算,不应用于整个SELECT ... FROM ... 集合,然后在where 子句中过滤?
      • @dfb,是的,基本上就是这样。您在 ROWNUM 上链接的文档解释了条件为 ROWNUM &gt; 1 的查询示例:“获取的第一行的 ROWNUM 为 1,使条件为假。要获取的第二行现在是第一行,也是将 ROWNUM 分配为 1 并使条件为假。随后所有行都不满足条件,因此不返回任何行。 ROWNUM 值是逐行分配的,然后根据 ROWNUM 上的任何条件进行检查,当行被拒绝时,相同的 ROWNUM 值将分配给下一个候选行。
      • @Dave Costa:感谢您的澄清。
      猜你喜欢
      • 2017-09-06
      • 2018-01-13
      • 1970-01-01
      • 2020-11-16
      • 2012-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      相关资源
      最近更新 更多