ORDER BY在PARTITION BY函数中的作用是什么?

Kar*_*hik 3 sql oracle sql-order-by partition-by

我有一张数据表,

    ID        SEQ    EFFDAT                 
------- ---------    -----------------------
  1024          1    01/07/2010 12:00:00 AM   
  1024          3    18/04/2017 12:00:00 AM   
  1024          2    01/08/2017 12:00:00 AM   
Run Code Online (Sandbox Code Playgroud)

当我执行以下查询时,我得到错误的最大序列仍然得到正确的最大生效日期.

查询:

SELECT 
max(seq) over (partition by id order by EFFDAT desc) maxEffSeq,
partitionByTest.*,
max(EFFDAT) over (partition by (id) order by EFFDAT desc ) maxeffdat
FROM partitionByTest;
Run Code Online (Sandbox Code Playgroud)

输出:

 MAXEFFSEQ         ID        SEQ EFFDAT                   MAXEFFDAT              
---------- ---------- ---------- ------------------------ ------------------------
         2       1024          2 01/08/2017 12:00:00 AM   01/08/2017 12:00:00 AM   
         3       1024          3 18/04/2017 12:00:00 AM   01/08/2017 12:00:00 AM   
         3       1024          1 01/07/2010 12:00:00 AM   01/08/2017 12:00:00 AM 
Run Code Online (Sandbox Code Playgroud)

如果我在查询中删除订单,我会得到正确的输出.

查询:

SELECT max(seq) over (partition by id ) maxEffSeq, partitionByTest.*,
max(EFFDAT) over (partition by (id) order by EFFDAT desc ) maxeffdat
FROM partitionByTest;
Run Code Online (Sandbox Code Playgroud)

输出:

 MAXEFFSEQ         ID        SEQ EFFDAT                   MAXEFFDAT              
---------- ---------- ---------- ------------------------ ------------------------
         3       1024          2 01/08/2017 12:00:00 AM   01/08/2017 12:00:00 AM   
         3       1024          3 18/04/2017 12:00:00 AM   01/08/2017 12:00:00 AM   
         3       1024          1 01/07/2010 12:00:00 AM   01/08/2017 12:00:00 AM   
Run Code Online (Sandbox Code Playgroud)

我知道当我们使用MAX函数时,不需要使用order by子句.但是我有兴趣知道按功能划分的顺序是如何工作的,以及当我使用order by子句时为什么它给出错误的序列结果和日期的正确结果?

Ale*_*ole 7

添加一个order by也意味着一个窗口子句,并且你没有指定一个你得到默认值,所以你真的在做:

max(seq) over (
  partition by id
  order by EFFDAT desc
  range between unbounded preceding and current row
)
Run Code Online (Sandbox Code Playgroud)

如果您考虑按照相同的方式订购数据的方式,请按降序日期:

select partitionbytest.*,
  count(*) over (partition by id order by effdat desc) range_rows,
  max(seq) over (partition by id order by effdat desc) range_max_seq,
  count(*) over (partition by id) id_rows,
  max(seq) over (partition by id) id_max_seq
from partitionbytest
order by effdat desc;

        ID        SEQ EFFDAT     RANGE_ROWS RANGE_MAX_SEQ    ID_ROWS ID_MAX_SEQ
---------- ---------- ---------- ---------- ------------- ---------- ----------
      1024          2 2017-08-01          1             2          3          3
      1024          3 2017-04-18          2             3          3          3
      1024          1 2010-07-01          3             3          3          3
Run Code Online (Sandbox Code Playgroud)

然后它变得更清晰一点.我已经包含了等效的分析计数,因此您还可以查看正在考虑的行数,包括和不包含该order by子句.

  • 对于第一行,最大seq值是通过查看当前行的数据和所有前面的行以及更晚的日期(因为它正在下降)找到的,并且没有这些,所以它是该行本身的值 - 所以它是2跟随它的行,seq值为3和1,不予考虑.

  • 对于第二行,它查看当前行和所有前面的行以及更晚的日期,因此它可以同时考虑前面的值2和当前值3.由于3在这些中最高,它显示了.后面跟着它的行,seq值为1,不予考虑.

  • 对于第三行,它查看当前行和所有前面的行以及更晚的日期,因此它可以考虑前面的值2和3以及当前值1.由于3仍然是最高的,它再次显示.

如果没有该order by子句,它始终会考虑该ID的所有值,因此它将3视为所有值的最高值.

有关如何确定分析函数的更多详细信息,请参阅文档以获取分析函数:

行组称为窗口,由analytic_clause定义.对于每一行,定义行的滑动窗口.该窗口确定用于执行当前行计算的行范围.窗口大小可以基于物理行数或逻辑间隔(例如时间).

除非已指定order_by_clause,否则无法指定[ windowing_clause ].

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


And*_*rew 5

这是正确的,虽然看起来很奇怪.

MAX上允许的order by子句是一个窗口函数,它允许order函数也包含一个windowing子句 - 所以通过指定order by子句然后你可以获取windowing子句的默认行为(因为你没有指定它).

默认是 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

文档:https://docs.oracle.com/database/121/SQLRF/functions004.htm#SQLRF06174

如果完全省略windowing_clause,那么默认值是UNBOUNDED PRECEDING和CURRENT ROW之间的RANGE.