我有一个查询,可以查询事件延迟的开始和结束时间,并计算CTE中的长度。单个事件可能会有多个延迟,但是由于用户错误,延迟可能同时发生。我想编写一个查询,将所有连续的延迟加在一起,包括按最早开始的延迟计算的并发运行的单个持续时间。
要获取数据表: 使用[tempdb]
GO
CREATE TABLE [dbo].[tblDelay](
[Delay_ID] [INT] NOT NULL,
[EventID] [INT] NOT NULL,
[D_Time] [Datetime] NOT NULL,
[D_EndTime] [Datetime]
)
GO
INSERT INTO tblDelay VALUES(1,1,'10:00','10:01');
INSERT INTO tblDelay VALUES(2,1,'10:05','10:06');
INSERT INTO tblDelay VALUES(3,1,'10:05:01','10:06');
INSERT INTO tblDelay VALUES(4,2,'10:00','10:01');
INSERT INTO tblDelay VALUES(5,2,'10:04','10:05');
INSERT INTO tblDelay VALUES(6,2,'10:06','10:07');
INSERT INTO tblDelay VALUES(7,2,'10:06:01','10:07');
INSERT INTO tblDelay VALUES(8,2,'10:10','10:12');
INSERT INTO tblDelay VALUES(8,2,'10:10:01','10:12');
我试图通过使用LEFT self-JOIN选择立即的下一个延迟,然后总结结果来做到这一点。我可以执行多个自联接,但是我希望它可以自动扩展,而不仅仅是测试一定数量的延迟。下面的代码有效:
WITH DelLength AS
(
SELECT
EventID, Delay_ID,
D_time, d_EndTime,
CAST(CAST(DATEDIFF(SECOND, D_Time, D_EndTime) AS DECIMAL(10, 2)) / 60 AS DECIMAL(10, 2)) AS DelLength
FROM
tblDelay d
)
SELECT
dl1.EventID,
dl1.D_Time,
dl1.D_EndTime,
(dl1.DelLength + dl2.DelLength + dl4.DelLength) AS Total
FROM
DelLength AS dl1
INNER JOIN
tblEvent e ON dl1.EventID = e.EventID
LEFT JOIN
DelLength AS dl2 ON dl1.EventID = dl2.EventID
AND dl2.D_Time = (SELECT TOP 1 dl3.D_Time
FROM DelLength dl3
WHERE dl3.EventID = dl1.EventID
AND dl3.D_Time > dl1.D_EndTime
ORDER BY dl3.D_Time)
LEFT JOIN
DelLength dl4 ON dl4.EventID = dl1.EventID
AND dl4.D_Time = (SELECT TOP 1 dl5.D_Time
FROM DelLength as dl5
WHERE dl5.EventID = dl1.EventID
AND dl5.D_Time > dl2.D_EndTime
ORDER BY dl5.D_Time)
为每个事件以及记录的第一,第二和第三后续延迟之和(如存在)产生一条记录。但是我要为无限多个后续延迟进行编码。
谢谢!
答案 0 :(得分:1)
您正在寻找一种解决方案,以按时间顺序虚拟化岛组。类似于以下查询的内容可能会有所帮助。虚拟化分组并获取每组的最小值和最大值,单个记录或非岛屿记录在下降时将按顺序排序,而一个岛内的所有记录将与该组中的第一条记录具有相同的顺序。
;WITH Markers AS
(
SELECT
*,
VirtualGroupID = SUM(IsNewGroup) OVER (ORDER BY D_Time ROWS UNBOUNDED PRECEDING)
FROM
(
SELECT
EventID, Delay_ID,
D_time, d_EndTime,
IsNewGroup = CASE WHEN ISNULL(LAG(EventID) OVER (ORDER BY D_Time),EventID)<>EventID THEN 1 ELSE 0 END
FROM
tblDelay d
)AS X
)
SELECT
EventID = MAX(EventId),
d_Time = MIN(d_Time),
d_EndTime = MAX(d_EndTime)
FROM
Markers
GROUP BY
VirtualGroupID
答案 1 :(得分:0)
非常感谢Ross使我走上正确的轨道。我发现您的答案是我所要查找方法的90%,只需在最里面的子查询中对窗口表达式进行详细说明即可对其进行补充。为了防止引入从上一个结束之前开始的延迟,我扩展了代码:
WITH Markers AS
(
SELECT
*,
VirtualGroupID = SUM(IsNewGroup) OVER (ORDER BY D_Time ROWS UNBOUNDED PRECEDING)
FROM
(
SELECT
EventID, Delay_ID,
D_time, d_EndTime,
IsNewGroup = CASE
WHEN
ISNULL(LAG(EventID) OVER (ORDER BY EventID, D_Time),EventID)<>EventID
OR
(LAG(EventID) OVER (ORDER BY EventID, D_Time) = EventID
AND D_Time > LAG(D_EndTime) OVER (ORDER BY EventID,D_Time))
THEN 1
ELSE 0 END
FROM
tblDelay d
)AS X
)
SELECT
EventID = MAX(EventId),
d_Time = MIN(d_Time),
d_EndTime = MAX(d_EndTime)
FROM
Markers
GROUP BY
VirtualGroupID
ORDER BY EventID
我认为这是正确的。
再次感谢!