使用和不使用 ORDER BY 子句的分区分析计数

Analytic count over partition with and without ORDER BY clause

我不明白为什么在解析 COUNT 函数中使用 ORDER BY 子句时会出现不同的结果。

使用一个简单的例子:

with req as
 (select 1 as n, 'A' as cls
    from dual
  union
  select 2 as n, 'A' as cls
    from dual)
select req.*, count(*) over(partition by cls) as cnt from req;

给出以下结果:

N   CLS CNT
2   A   2
1   A   2

而在解析子句中加入ORDER BY,结果就不一样了!

with req as
 (select 1 as n, 'A' as cls
    from dual
  union
  select 2 as n, 'A' as cls
    from dual)
select req.*, count(*) over(partition by cls order by n) as cnt from req;

CNT 列已更改:

N   CLS CNT
1   A   1
2   A   2

有人可以解释一下吗?

谢谢

首先,link 文档。然而,它有点模糊。

解析子句由query_partition_clauseorder_by_clausewindowing_clause组成。而且,关于 windowing_clause 的一个非常重要的事情是

You cannot specify this clause unless you have specified the order_by_clause. Some window boundaries defined by the RANGE clause let you specify only one expression in the order_by_clause. Refer to "Restrictions on the ORDER BY Clause".

但是,如果没有 order_by_clause,您不仅不能使用 windowing_clause,而且它们是捆绑在一起的。

If you omit the windowing_clause entirely, then the default is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.

默认的 windowing 子句产生类似 运行 的结果。 COUNT returns 1 第一行,因为 window 的顶部和当前行之间只有一行,第二行 2 和等等。

因此在您的第一个查询中根本没有 windowing,但是在第二个查询中有默认的 windowing。

并且您可以通过指定完全无界来模拟第一个查询的行为window。

with req as
 (select 1 as n, 'A' as cls
    from dual
  union
  select 2 as n, 'A' as cls
    from dual)
select req.*, count(*) over(partition by cls order by n RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as cnt from req;

是的

N   CLS CNT
1   A   2
2   A   2

最简单的思考方式 - 将 ORDER BY 排除在外等同于 "ordering",分区中的所有行彼此 "equal"。实际上,您可以通过显式添加 ORDER BY 子句来获得相同的效果,如下所示:ORDER BY 0(或 "order by" any 常量表达式),甚至, 更强调的是, ORDER BY NULL.

为什么你得到整个分区的 COUNT()SUM() 等与默认窗口子句有关:RANGE between unbounded preceding and current row。 "Range"(与 "ROWS" 相对)意味着包含当前行的所有行 "tied" 也包括在内,即使它们不在当前行之前。由于所有行都绑定,这意味着整个分区都包括在内,无论哪一行是 "current."

Window 函数将对按(拆分)值的分区执行聚合,当您省略 ORDER BY 子句时,结果将类似于 GROUP BY 每行的输出。也可以省略 PARTITION BY,在这种情况下只有一个分区包含所有行

当您将 ORDER BY 子句添加到 window 函数时,它将在同一分区内按后续顺序执行计算,并从不同的分区(值组)重新开始

ORDER BY 顺序中不明显的值被称为对等值,在 COUNT() 中,它们将具有与其最后一个对等值相同的计算结果,这将产生间隙以保持总计