ale*_*lex 6 sql sql-server-2008 gaps-and-islands
我有下表,其中包含来自几个不同设备的每15分钟读取的值:
ID DeviceID Date Value
----------------------------------------------
1 3 24.08.2011 00:00:00 0.51
2 3 24.08.2011 00:15:00 2.9
3 3 24.08.2011 00:30:00 0
4 3 24.08.2011 00:45:00 7.1
5 3 24.08.2011 01:00:00 1.05
6 3 24.08.2011 03:15:00 3.8
Run Code Online (Sandbox Code Playgroud)
我想在给定月份的每个设备中查找表中的所有空白,其中没有条目.对于上表,结果应该是这样的:
DeviceID StartDate EndDate
-------------------------------------------------------
3 24.08.2011 01:00:00 24.08.2011 03:15:00
Run Code Online (Sandbox Code Playgroud)
该表有大约35000个设备和1亿个条目.
这就是我的尝试; 它很慢,但返回我需要的东西.然而,除了它的速度之外,还有另一个问题:它只发现在给定月份内设备的最后一个条目的丢失间隔; 之后的任何内容都将被忽略,因此可能会错过额外的缺失值间隔.
SELECT
t2.Date AS StartDate
, t1.Date AS EndDate
FROM
TestTable t1
INNER JOIN TestTable t2 ON t1.DeviceID = t2.DeviceID
WHERE
(t2.Date = (SELECT MAX(Date) FROM TestTable t3 WHERE t3.Date < t1.Date AND t3.DeviceID = t1.DeviceID)
AND DATEDIFF(MINUTE, t2.Date, t1.Date) > 15)
AND t1.DeviceID = @id
AND DATEPART(YEAR, t1.Date) = @year AND DATEPART(MONTH, t1.Date) = @month
Run Code Online (Sandbox Code Playgroud)
以下应该工作,并且不返回deviceid的单个记录.
这个的要点是
Date并重新启动DeviceID.DeviceID.Date时间超过15分钟的行.SQL语句
;WITH t AS (
SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY DeviceID ORDER BY Date)
FROM TestTable
)
SELECT t1.DeviceID, t1.Date, t2.Date
FROM t t1
INNER JOIN t t2 ON t2.DeviceID = t1.DeviceID AND t2.rn = t1.rn + 1
WHERE DATEDIFF(MINUTE, t1.Date, t2.Date) > 15
Run Code Online (Sandbox Code Playgroud)
测试脚本
;WITH TestTable (ID, DeviceID, Date, Value) AS (
SELECT 1, 3, '2011-08-24 00:00:00', 0.51 UNION ALL
SELECT 2, 3, '2011-08-24 00:15:00', 2.9 UNION ALL
SELECT 3, 3, '2011-08-24 00:30:00', 0 UNION ALL
SELECT 4, 3, '2011-08-24 00:45:00', 7.1 UNION ALL
SELECT 5, 3, '2011-08-24 01:00:00', 1.05 UNION ALL
SELECT 6, 3, '2011-08-24 03:15:00', 3.8
)
, t AS (
SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY DeviceID ORDER BY Date)
FROM TestTable
)
SELECT t1.DeviceID, t1.Date, t2.Date
FROM t t1
INNER JOIN t t2 ON t2.DeviceID = t1.DeviceID AND t2.rn = t1.rn + 1
WHERE DATEDIFF(MINUTE, t1.Date, t2.Date) > 15
Run Code Online (Sandbox Code Playgroud)