SQL 服务器: 查找最近连续大于 5 的记录

SQL Server : find recent consecutive records that are greater than 5

我需要编写一个查询,根据最近的 LogDate.

显示按 FormID 细分的结果,其值大于 5

根据最近的 LogDate,如果有一个值小于 5,它应该显示从那个点开始大于 5 的值,因为小于 5 的值是 'reset' 如果你愿意的话。

我实际上是在查看最近连续 LogDate 条大于 5 的记录。

假设我们有以下记录集:

FormID   Value  LogDate    
--------------------------
Form2    6      10/12/19   
Form2    7      10/13/19   
Form1    8      10/12/19
Form1    12     10/12/19
Form1    3      10/14/19
Form1    8      10/15/19
Form1    6      10/21/19  

以下将 return 以下(请注意我也想显示 row_num:

 FormID   Value  LogDate   row_num
 ----------------------------------
 Form2    6      10/12/19  1
 Form2    7      10/13/19  2
 Form1    8      10/15/19  1
 Form1    6      10/21/19  2

注意上面的例子,因为下面的记录最近的值小于5(值为3),所以我们需要获取大于5的记录。

另一个例子:

FormID   Value  LogDate     
Form1    8      10/15/19
Form1    3      10/21/19  

RESULT: 不会显示结果,因为最近的记录大于 5

另一个例子:

FormID   Value  LogDate    
Form2    4      10/12/19   
Form2    3      10/13/19   
Form1    16     10/12/19
Form1    3      10/12/19
Form1    3      10/14/19
Form1    8      10/15/19
Form1    12     10/21/19 

这里的结果是:

FormID   Value  LogDate   row_num
Form1    8      10/15/19  1
Form1    12     10/21/19  2

另一个例子:

FormID   Value  LogDate    
Form1    12      10/12/19   
Form2    13      10/13/19  

结果:

FormID   Value  LogDate    row_num
Form1    12      10/12/19  1 
Form2    13      10/13/19  2

据我了解,这可以通过 LAG 函数来完成,但不确定如何将其完全放在一起。

我们可以这样做:

   DECLARE @mytable TABLE
   (
     FormID VARCHAR(50), 
     [Value] INT, 
     LogDate DATETIME
    )

    select t.*, 
        lag(value) over(partition by formid order by logdate) lag_value
    from @mytablet

但不确定如何将它们整合在一起。

一种方法是:

select t.*,
       row_number() over (partition by formid order by logdate)
from t
where t.logdate > (select coalesce(max(t.logdate), '2000-01-01')
                   from t t2
                   where t2.formid = t.formid and t.value <= 5
                  );

您还可以使用 window 函数:

select t.*,
       row_number() over (partition by formid order by logdate)
from (select t.*,
             max(case when value <= 5 then logdate end) over (partition by formid) as logdate_5
      from t
     ) t
where logdate_5 is null or
      date > logdate_5
order by formid, logdate;

如果我没听错的话,你可以用 window 函数来做到这一点:

select 
from (
    select t.*, 
        row_number() over(partition by formid order by logdate desc) rn,
        sum(case when value > 5 then 1 else 0 end) over(partition by formid order by logdate desc) grp
    from mytable t
) t
where rn = grp

想法是将 5 以上的值的数量与行号进行比较,从最近的值开始计算。可以保留两个值相等的行。

fiddle 中找到指示性答案。

reset_calendar 是重置发生的日期,用于过滤数据。

SELECT temp.*,
       ROW_NUMBER() OVER (PARTITION BY temp.FormID ORDER BY temp.LogDate) AS Sequence
FROM (
  SELECT t.*
  FROM t
  LEFT JOIN (
    SELECT FormID, MAX(LogDate) AS recent_reset 
    FROM t
    WHERE Value<6
    GROUP BY FormID) AS reset_calendar
  ON t.FormID = reset_calendar.FormID
  WHERE t.LogDate > reset_calendar.recent_reset OR reset_calendar.recent_reset IS NULL)temp