3

我有一个数据表,

    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   

当我执行以下查询时,我得到了错误的最大序列,但我得到了正确的最大有效日期。

询问:

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;

输出:

 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 

如果我在查询中删除 order by,我会得到正确的输出。

询问:

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

输出:

 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   

我知道当我们使用 MAX 函数时,不需要使用 order by 子句。但是我很想知道 order by 如何在按功能分区中工作,以及为什么当我使用 order by 子句时它给出了错误的序列结果和正确的日期结果?

4

2 回答 2

7

添加一个order by也意味着一个窗口子句,并且由于您没有指定一个,您将获得默认值,所以您确实在做:

max(seq) over (
  partition by id
  order by EFFDAT desc
  range between unbounded preceding and current row
)

如果您考虑以相同方式排序数据的外观,按降序排列:

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

然后它变得更清楚了。我已经包含了等效的分析计数,因此您还可以看到正在考虑的行数,有和没有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.

于 2018-08-09T08:02:34.993 回答
5

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

MAX 上允许的 order by 子句是一个窗口函数,它允许 order 函数也包含一个窗口子句 - 因此通过指定一个 order by 子句,您可以选择窗口子句的默认行为(因为你没有指定它)。

默认是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

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

如果您完全省略 windowing_clause,则默认值为 RANGE BETWEEN UNBOUNDED PRECEDING 和 CURRENT ROW。

于 2018-08-09T08:02:28.603 回答