SQL Server:查找大于 5 的最近连续记录

Posted

技术标签:

【中文标题】SQL Server:查找大于 5 的最近连续记录【英文标题】:SQL Server : find recent consecutive records that are greater than 5 【发布时间】:2020-11-09 14:42:04 【问题描述】:

我需要编写一个查询,显示由FormID 分解的结果,根据最新的LogDate 其值大于5。

根据最近的LogDate,如果有一个小于 5 的值,它应该显示从该点开始大于 5 的值,因为如果你愿意,低于 5 的值是一个“重置”。

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

假设我们有以下记录集:

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  

以下将返回以下内容(请注意,我也喜欢显示 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

但不知道如何将它们组合在一起。

【问题讨论】:

到目前为止你尝试过什么?为什么它不起作用?否则,你做过哪些研究,哪些方面你不了解? @Larnu 添加了有关延迟可以做什么的信息。 【参考方案1】:

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

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 以上的值的数量与行号进行比较,从最近的值开始计数。可以保留两个值相等的行。

【讨论】:

感谢您的回复。我使用示例 1 中的示例数据进行了尝试,但没有返回正确的结果。它返回了 6 个结果。它应该只返回 4 个结果。请注意,我正在寻找自上次低于 5 以来大于 5 的结果集,或者如果之前没有低于 5 的结果集,那么自我们保持记录以来。 @NatePet:sum() 窗口中有错字(logdate 而不是value)。固定 谢谢。我喜欢你的解决方案。我仍在测试它,我想我找到了它不起作用的地方。请给我更多的时间来测试,我会跟进。再次感谢您。 @NatePet:一个潜在的问题是,如果您有相同的logdates 和相同的formid。它使排序不确定。您需要一组唯一标识每一行的列。 是的,在我的现实生活中,它是一个独特的日期戳,所以效果很好。感谢您的所有帮助。我接受了你的回答。【参考方案2】:

在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

【讨论】:

【参考方案3】:

一种方法是:

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
                  );

你也可以使用窗口函数:

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;

【讨论】:

谢谢。似乎示例 2 有效,但您可以对其进行更新,以便它也显示 row_num。也例如1,我无法让它工作。您能否在查询中替换我的表名(@mytable),我可以再试一次。当我尝试它时,它说:“聚合可能不会出现在 WHERE 子句中,除非它位于 HAVING 子句或选择列表中包含的子查询中,并且被聚合的列是外部引用。” 同样在示例 2 中,它的数据顺序是正确的,但我们是否应该放置以下内容以使其在所有情况下都能正常工作:partition by formid order by logdate

以上是关于SQL Server:查找大于 5 的最近连续记录的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server:查找学生在自定义日期内的连续缺勤计数

sql 语句:一个字段,连续几天值大于0,获得天数

在 SQL Server 中查找最近的日期

在 SQL Server 中查找非连续日期

如何在 SQL Server 的多行中查找连续的日期

如何用sql查询出连续三个月金额大于50的记录