tsql检查事件是否在特定频率内发生

时间:2015-11-17 16:42:25

标签: sql-server tsql

我有一张发生过失败事件的表。我需要找出例如两分钟内是否记录了五次失败。

Id  Created                  EventType  Description
1   2015-11-16 15:10:16      1         test
2   2015-11-16 15:12:17      1         test
3   2015-11-16 15:12:18      1         test
4   2015-11-16 15:12:19      1         test
5   2015-11-16 15:12:20      1         test
6   2015-11-16 15:13:16      1         test
7   2015-11-16 16:15:43      1         test

所以在这个例子中,将选择事件2-6。然后我需要选择期间的开始和结束时间。

甚至不知道从哪里开始,显然它是在比较两行。我想过使用光标但不确定是否有任何我可以使用的聪明分组。

2 个答案:

答案 0 :(得分:1)

不是全部,但应该让你开始

UsedRange.Value

如果您知道ID将按顺序使用,可以在t2.ID>上使用t1.ID

这可能不是我从内存中做到的确切的DateDiff语法

假设你在一个范围内有7个。这将报告任何(多个)5组。您需要对您想要的内容非常具体。

答案 1 :(得分:1)

您可以使用CROSS APPLY初步选择事件2-6:

SELECT t1.Id, t1.EventType, t1.Created AS StartTime, t3.EndTime
FROM mytable AS t1
CROSS APPLY (
   SELECT TOP 1 t2.Id, t2.Created 
   FROM mytable AS t2
   WHERE t1.EventType = t2.EventType AND
         t2.Id <> t1.Id AND
         ABS(DATEDIFF(ss, t1.Created, t2.Created)) <= 60 
   ORDER BY DATEDIFF(ss, t1.Created, t2.Created) DESC) AS t3(Id, EndTime)

<强>输出:

Id  EventType   StartTime               EndTime
2   1           2015-11-16 15:12:17.000 2015-11-16 15:13:16.000
3   1           2015-11-16 15:12:18.000 2015-11-16 15:13:16.000
4   1           2015-11-16 15:12:19.000 2015-11-16 15:13:16.000
5   1           2015-11-16 15:12:20.000 2015-11-16 15:13:16.000
6   1           2015-11-16 15:13:16.000 2015-11-16 15:12:20.000

您现在可以检查记录存储桶是否包含5行或更多行,并使用GROUP BY获取第一个/最后一个记录:

SELECT MIN(t1.Id) AS StartID, 
       MAX(t3.Id) AS EndID, 
       t1.EventType, 
       MIN(t1.Created) AS StartTime, MAX(t3.EndTime) AS EndTime
FROM mytable AS t1
CROSS APPLY (
   SELECT TOP 1 t2.Id, t2.Created 
   FROM mytable AS t2
   WHERE t1.EventType = t2.EventType AND
         t2.Id <> t1.Id AND
         ABS(DATEDIFF(ss, t1.Created, t2.Created)) <= 120 
   ORDER BY DATEDIFF(ss, t1.Created, t2.Created) DESC) AS t3(Id, EndTime)
GROUP BY t1.EventType
HAVING COUNT(*) >= 5

<强>输出:

StartID EndID   EventType   StartTime               EndTime
2       6       1           2015-11-16 15:12:17.000 2015-11-16 15:13:16.000

修改

另一种方法是使用Recursive CTE

;WITH CTE_RN AS (
   SELECT Id, EventType, Created,
          ROW_NUMBER() OVER (ORDER BY Created) AS rn
   FROM mytable
), CTE_Buckets AS (
   -- Anchor member: Get first row from table
   SELECT Id, EventType, Created, CAST(1 AS BIGINT) AS row_num,
          1 AS bucket_num, 0 AS time_diff
   FROM CTE_RN
   WHERE rn = 1

   UNION ALL

   -- Recursive member: Get next row. Reset time diff cumulative counter
   -- if time difference exceeds two minutes
   SELECT c1.Id, c1.EventType, c1.Created, c1.rn AS row_num, 
          -- All consecutive rows within the 2 minute time range fall within the same bucket
          bucket_num = CASE 
                          WHEN x.diff + time_diff > 120 THEN c2.bucket_num + 1
                          ELSE c2.bucket_num 
                       END,
          -- Calculate cummulative time diff. 
          time_diff = CASE 
                         WHEN x.diff + time_diff > 120 THEN 0
                         ELSE x.diff + time_diff
                      END
   FROM CTE_RN AS c1
   INNER JOIN CTE_Buckets AS c2 ON c1.rn = c2.row_num + 1
   CROSS APPLY (SELECT DATEDIFF(ss, c2.Created, c1.Created)) AS x(diff)
)   
SELECT MIN(Id) AS StartID, MAX(Id) AS EndID, 
       MIN(Created) AS StartTime, MAX(Created) AS EndTime
FROM CTE_Buckets
GROUP BY bucket_num   
HAVING COUNT(*) >= 5

此查询处理多个间隔组。