SQL 窗口函数 - 自上次 Max 以来的行数

Posted

技术标签:

【中文标题】SQL 窗口函数 - 自上次 Max 以来的行数【英文标题】:SQL Window Function - Number of Rows since last Max 【发布时间】:2019-07-27 00:42:35 【问题描述】:

我正在尝试创建一个 SQL 查询,该查询将在过去 5 行中提取自 windows 函数中的最后一个最大值以来的行数。在下面的示例中,它将为第 8 行返回 2。最大值为 12,即第 8 行的 2 行。

对于第 6 行,它将返回 5,因为 7 的最大值在 5 行之外。

|ID  | Date       | Amount  
| 1  | 1/1/2019   |  7  
| 2  | 1/2/2019   |  3  
| 3  | 1/3/2019   |  4  
| 4  | 1/4/2019   |  1  
| 5  | 1/5/2019   |  1  
| 6  | 1/6/2019   |  12  
| 7  | 1/7/2019   |  2  
| 8  | 1/8/2019   |  4  

我尝试了以下方法:

SELECT ID, date, MAX(amount) 
OVER (ORDER BY date ASC ROWS 5 PRECEDING) mymax
FROM tbl 

这让我达到最大值,但我无法有效地确定它有多少行。我能够在 SELECT 中使用多个变量来接近,但这似乎没有效率或可扩展性。

【问题讨论】:

以表格格式显示预期输出。 【参考方案1】:

您可以计算累积最大值,然后在上面使用row_number()

所以:

select t.*,
       row_number() over (partition by running_max order by date) as rows_since_last_max
from (select t.*, 
             max(amount) over (order by date rows between 5 preceding and current row) as running_max
      from tbl t
     ) t;

我认为这适用于您的示例数据。如果您有重复,它可能无法正常工作。

在这种情况下,您可以使用日期算术:

select t.*,
       datediff(day,
                max(date) over (partition by running_max order by date),
                date
               ) as days_since_most_recent_max5
from (select t.*, 
             max(amount) over (order by date rows between 5 preceding and current row) as running_max
      from tbl t
     ) t;

编辑:

这里是一个使用行号的例子:

select t.*,
       (seqnum - max(case when amount = running_amount then seqnum end) over (partition by running_max order by date)) as rows_since_most_recent_max5
from (select t.*, 
             max(amount) over (order by date rows between 5 preceding and current row) as running_max,
             row_number() over (order by date) as seqnum
      from tbl t
     ) t;

【讨论】:

感谢您的回复,但我仍然遇到问题。我的“金额”确实有重复的数字,这会导致问题。然后我尝试了您提供的第二个示例,但是我的源数据的日期存在差距。这会产生不准确的结果。我真的需要最近的最大行数而不是 datediff。任何额外的帮助将不胜感激。 @JDG 。 . .您明确声明您想要前五行,因此日期中的空白应该无关紧要。如果它们是一个问题,我建议您提出一个新的问题,并提供适当的样本数据、期望的结果和解释。 嗨,戈登。没错,它应该是前 5 行中的最大值。 datediff 函数计算日期之间的差异,而不是行中的差异。例如,日期可以按 10/1/2019、10/2/2019、10/5/2019、10/10/2019 的顺序排列。 datedff 将提供与行差异不匹配的“days_since_most_recent_max5”。 @JDG 。 . .在这种情况下,您可以使用 id 而不是 date - 如果您的 id 没有间隙并且始终递增 1。 是的,这就是我最初在您的第一个示例中尝试的方法。问题是查询的第一部分中有重复的“running_max”。当查询的第二部分查找 row_number 时,它选择了不正确的记录。在许多情况下,rows_since_last_max 返回的值超过 5。这是因为它在正确的实例之前找到了重复的 running_max。【参考方案2】:

应该是:

select *,ID- 
(
SELECT ID
FROM
  (
    SELECT
      ID,amount,
      Maxamount =q.mymax
    FROM
      Table_4 
  ) AS derived
WHERE
  amount = Maxamount
) as result
from (

    SELECT ID, date,
    MAX(amount) 
    OVER (ORDER BY date ASC ROWS 5 PRECEDING) mymax
    FROM Table_4 
)as q

【讨论】:

以上是关于SQL 窗口函数 - 自上次 Max 以来的行数的主要内容,如果未能解决你的问题,请参考以下文章

窗口函数

Hive窗口函数保姆级教程

获取过去 7 天以来的行数

Sql 复习

错误:找不到要更新的行。自上次读取以来,某些值可能已更改。关于将提供程序从 SQLOLEDB 更改为 MSOLEDBSQL

如果自上次事件以来传感器读数没有更改,则如何在未发送传感器读数时计算窗口上的聚合?