使用和不使用ORDER BY子句对分区进行分析计数

时间:2016-12-28 15:06:15

标签: sql oracle window-functions

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

使用一个简单的例子:

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

有人可以解释一下吗?

由于

2 个答案:

答案 0 :(得分:5)

首先,link到文档。然而,这有点模糊不清。

分析条款由query_partition_clauseorder_by_clausewindowing_clause组成。而且,关于windowing_clause的一个非常重要的事情是

  

除非已指定,否则不能指定此子句   order_by_clause。由RANGE子句定义的一些窗口边界   让您只在order_by_clause中指定一个表达式。参考   "对ORDER BY条款的限制"。

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

  

如果完全省略windowing_clause,则默认为RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

默认的窗口子句产生类似于运行总计的内容。 COUNT为第一行返回1,因为窗口顶部和当前行之间只有一行,第二行只有2,依此类推。

因此,在您的第一个查询中,根本没有 no 窗口,但第二个窗口中存在默认窗口。

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

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

答案 1 :(得分:3)

考虑这一点的最简单方法 - 让ORDER BY离开等同于“排序”,使得分区中的所有行彼此“相等”。实际上,您可以通过显式添加ORDER BY这样的ORDER BY 0子句来获得相同的效果:ORDER BY NULL(或“按”任何常量表达式排序),甚至更重要的是, COUNT()

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