Sql-Server
計數不在時間範圍內的項目
如果它們不在“組”中第一個項目的 30 秒內,我正在嘗試計算項目的數量。我很難弄清楚這一點。
所以,我有這張桌子:
WITH ADates AS ( SELECT Id , SharedId , TheDateTime FROM (VALUES (CAST(1 AS int), CAST(1 AS int), CAST('2019-01-01 01:01:00.00' AS datetime2(7))), (2, 1, '2019-01-01 01:01:33.00'), (3, 1, '2019-01-01 01:02:00.00'), (4, 1, '2019-01-01 01:02:01.00'), (5, 1, '2019-01-01 01:02:04.00'), (6, 1, '2019-01-01 01:06:15.00'), (7, 2, '2019-01-01 01:06:00.00'), (8, 2, '2019-01-01 01:06:45.00'), (9, 1, '2019-01-01 01:02:31.00'), (10, 2, '2019-01-01 01:06:05.00'), (11, 2, '2019-01-01 01:06:46.00'), ) X (Id, SharedId, TheDateTime) )
所以,我正在尋找的預期結果是:
+==========+=======+ | SharedId | Count | +==========+=======+ | 1 | 4 | +----------+-------+ | 2 | 2 | +----------+-------+
數字由以下因素決定:
- 從新組中的第一個開始計數。
- 不在前一組的 30 秒內,因此它是一個新組併計數。
- 不要計算,因為它在 2 的 30 秒內。
- 不要計算,因為它在 2 的 30 秒內。
- 從前一組的 30 秒內開始計數(第 2 項)。
- 從前一組的 30 秒內開始計數(第 2 項)。
- 計算 SharedId 的新組。
- 計數,因為不在先前的分組內。
我想我應該為此做一個
Window Function
。只是不知道如何讓它依賴於小組中的第一個。
問題分類
我一直在尋找一種方法來使用跟踪內聯操作的分析函式。單個執行分析函式只能執行這麼多,但不能擴展到解決這個問題。嵌套分析函式的問題是我們失去了關於動態模式的資訊。
要允許動態內聯模式匹配,您可以在Oracle中使用MATCH_RECOGNIZE。不過,我不知道如何在Sql Server中執行此操作。然後我遇到了一個類似的問題,使用遞歸 CTE解決了這個問題。
建議的解決方案
- SharedId GroupStartDateTime - 1 01/01/2019 01:01:00 - 1 01/01/2019 01:01:33 - 1 01/01/2019 01:02:04 - 1 01/01/2019 01:06:15 - 2 01/01/2019 01:06:00 - 2 01/01/2019 01:06:45 6 rows
CteBase
並且CteRecursive
受到Bogdan Sahlean 對這個相關問題的回答的極大啟發。WITH CteBase AS ( SELECT v.SharedId, v.TheDateTime, ROW_NUMBER() OVER(PARTITION BY v.SharedId ORDER BY v.TheDateTime) AS RowNum FROM ADates v ), CteRecursive AS ( SELECT crt.SharedId, crt.TheDateTime, crt.TheDateTime AS GroupStartDateTime, crt.RowNum, 1 AS SharedIdRowNum FROM CteBase crt WHERE crt.RowNum = 1 UNION ALL SELECT crt.SharedId, crt.TheDateTime, CASE WHEN DATEDIFF(SECOND, prv.GroupStartDateTime, crt.TheDateTime) <= 30 THEN prv.GroupStartDateTime ELSE crt.TheDateTime END, crt.RowNum, CASE WHEN DATEDIFF(SECOND, prv.GroupStartDateTime, crt.TheDateTime) <= 30 THEN prv.SharedIdRowNum + 1 ELSE 1 END FROM CteBase crt INNER JOIN CteRecursive prv ON crt.SharedId = prv.SharedId AND crt.RowNum = prv.RowNum + 1 ) SELECT SharedId, Count(*) as [COUNT] FROM ( SELECT r.SharedId, r.GroupStartDateTime FROM CteRecursive r WHERE r.SharedIdRowNum = 1 ) X GROUP BY SharedId;