2016-04-28 63 views
3

我有一個表跟蹤爲特定的Device_IDs創建的Incident_IDs的Datetime,我試圖找到一種方法來跟蹤日期範圍內的慢性問題。慢性問題的定義是在過去5天內創建了3個或更多Incident_ID的任何Device_ID。我需要能夠搜索一系列不同的日期(通常是每月)。MS SQL 2014 - 在日期範圍內重複出現的次數

鑑於表:

IF OBJECT_ID('tempdb.dbo.#temp') IS NOT NULL 
DROP TABLE #temp 

CREATE TABLE #temp 
    (Device_ID INT, 
    Incident_ID INT, 
    Incident_Datetime DATETIME) 

INSERT INTO #temp 
VALUES 
    (2,1001,'2016-02-01'), 
    (3,1002,'2016-02-02'), 
    (2,1003,'2016-02-09'), 
    (2,1004,'2016-02-10'), 
    (5,1005,'2016-02-12'), 
    (2,1006,'2016-02-13'), 
    (5,1007,'2016-02-14'), 
    (5,1008,'2016-02-15'), 
    (3,1009,'2016-02-18'), 
    (3,1010,'2016-02-19'), 
    (3,1011,'2016-02-20'), 
    (5,1012,'2016-02-21'), 
    (3,1013,'2016-03-18'), 
    (3,1014,'2016-03-19'), 
    (3,1015,'2016-03-20'); 

爲02-2016慢性問題期望的結果是:

Device_ID Incident_ID Incident_Datetime 
2   1003   2/9/16 0:00 
2   1004   2/10/16 0:00 
2   1006   2/13/16 0:00 
3   1009   2/18/16 0:00 
3   1010   2/19/16 0:00 
3   1011   2/20/16 0:00 
5   1005   2/12/16 0:00 
5   1007   2/14/16 0:00 
5   1008   2/15/16 0:00 

我曾嘗試下面的查詢,顯示我的事件的上升計數和讓我找到那些長期存在問題的device_id,但我很難隔離構成慢性問題的所有事件,同時排除在3天範圍之外發生的異常值。

SELECT c.Device_ID, c.Incident_ID, c.Incident_Datetime, 
    (SELECT COUNT(*) 
    FROM #temp AS t 
    WHERE 
     c.Device_ID = t.Device_ID 
     AND 
     t.Incident_Datetime BETWEEN DATEADD(DAY,-5,c.Incident_Datetime) AND c.Incident_Datetime) AS Incident_Count 
FROM #temp AS c 
WHERE 
    c.Incident_Datetime >= '2016-02-01' 
    AND 
    c.Incident_Datetime < '2016-03-01' 
ORDER BY 
    Device_ID, Incident_Datetime 

回答

1

這可能是不太一樣好傑克的答案,但這裏可能工作的替代解決方案:

 WITH cte AS 
     (
      SELECT tmp.Device_ID, tmp.Incident_Datetime FROM #temp AS tmp 
      CROSS APPLY 
      ( 
      SELECT Device_ID 
      FROM #temp AS t 
      WHERE tmp.Device_ID = t.Device_ID AND t.Incident_Datetime BETWEEN DATEADD(d,-5,tmp.Incident_Datetime) AND tmp.Incident_Datetime 
      GROUP BY Device_ID HAVING COUNT(Incident_ID) >= 3 
     ) p 
      WHERE tmp.Incident_Datetime BETWEEN '02-01-2016' AND '03-01-2016' 
     )   

     SELECT f.* 
     FROM #temp f 
     INNER JOIN cte 
     ON f.Device_ID = cte.Device_ID 
     WHERE f.Incident_Datetime BETWEEN DATEADD(d,-5,cte.Incident_Datetime) AND cte.Incident_Datetime 
     GROUP BY f.Device_ID, f.Incident_ID, f.Incident_Datetime 
     ORDER BY f.Device_ID, f.Incident_Datetime 
+0

真棒,這個工程,並且正是我需要克服這個問題給我的心理障礙的替代方法。我將需要磨合CROSS APPLY,因爲它們不是我經常使用的東西,但它確實有效! – Jericho

+0

這是我第一次真正使用它自己。它給了我很多關於如何在將來使用它的想法。所以我很欣賞心理鍛鍊。 :) –

0

這個怎麼樣...

DECLARE @StartDate datetime, @EndDate datetime 
SET @StartDate='2016-02-01' 
SET @EndDate='2016-03-01' 

SELECT c.Device_ID, c.Incident_ID, c.Incident_DateTime FROM #temp c 
INNER JOIN (SELECT t.Device_ID, Count(*) FROM #temp 
    WHERE t.Incident_DateTime BETWEEN DATEADD(dd, -3, c.Incident_DateTime) AND DATEADD(dd, +3, c.Incident_DateTime) 
    GROUP BY t.Device_ID 
    HAVING Count(*) > 2)) t ON c.Device_ID = t.Device_ID 
AND c.Incident_DateTime BETWEEN @StartDate AND @EndDate 
ORDER BY 
c.Device_ID, c.Incident_Datetime 
+0

我不能得到這個工作。看起來在HAVING COUNT(*)後面有一個額外的圓括號,但它不能綁定t。和c。內部連接查詢的標識符 – Jericho

0

下面是內n天總得出一個正在運行的事件的方式:

with 
incidents as (
    select * from #temp cross apply (
    select incident_datetime, 1 union all 
    select incident_datetime + 5, -1) x(dt, delta)), 
rolling as (
    select *, incidents_in_range = sum(delta) 
     over (partition by device_id order by dt) 
    from incidents) 

select t.* from #temp t join rolling r 
    on r.device_id=t.device_id 
    and t.incident_datetime between r.incident_datetime - 5 and r.incident_datetime 
where r.incidents_in_range >= 3 

..basically找到點,其中「3 5天內發生的事件「,然後在5天內加入事件。

+0

感謝您指出device_id問題,我在製作日期時沒有給予足夠的關注。我編輯了答案以刪除它們。當我運行你的查詢時,我收到了一些奇怪的結果 - device_id 2,incident_id 1004顯示出來(這是唯一的device_id 2條目),而且incident_datetime不正確。例如:對於device_id 5,incident_id 1005,它顯示爲2016-02-15,它應該是2016-02-12(看起來像是使用UNION ALL語句的datetime) – Jericho

+0

@Jericho添加了一個修復程序incident_datetime來自所有工會的另一面。 – gordy