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

car*_*ose 10 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;
Run Code Online (Sandbox Code Playgroud)

给出以下结果:

N   CLS CNT
2   A   2
1   A   2
Run Code Online (Sandbox Code Playgroud)

然而,当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;
Run Code Online (Sandbox Code Playgroud)

CNT专栏改变了:

N   CLS CNT
1   A   1
2   A   2
Run Code Online (Sandbox Code Playgroud)

有人可以解释一下吗?

谢谢

Tha*_*man 7

首先,链接到文档.然而,这有点模糊.

分析条款包括query_partition_clause,order_by_clausewindowing_clause.而且,一个非常重要的事情windowing_clause

除非已指定,否则不能指定此子句 order_by_clause.该RANGE子句定义的某些窗口边界允许您仅指定一个表达式order_by_clause.请参阅"ORDER BY子句的限制".

但是,不仅可以不使用windowing_clauseorder_by_clause,他们是联系在一起的.

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

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

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

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

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;
Run Code Online (Sandbox Code Playgroud)

是的

N   CLS CNT
1   A   2
2   A   2
Run Code Online (Sandbox Code Playgroud)

  • 默认窗口子句仅在ORDER BY子句产生总排序(没有关系)的特殊情况下产生"运行计数".默认的window子句使用`RANGE between ...之间而不是`之间的'ROWS ... - 所以`ORDER BY`度量相同的行也将具有相同的`COUNT`.要在这些情况下获得真正的"运行计数",需要添加一个显式窗口子句,"无界前行和当前行之间的行".除此之外,很好的答案! (2认同)

mat*_*guy 5

考虑这一点的最简单方法 - 将ORDER BYout 排除在外相当于以分区中的所有行彼此“相等”的方式“排序”。实际上,您可以通过显式添加这样的ORDER BY子句来获得相同的效果:( ORDER BY 0或“order by”任何常量表达式),或者甚至更强调的是,ORDER BY NULL.

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