卡在涉及时间段的 Gaps and Islands 查询上
Stuck on a Gaps and Islands query involving time periods
我有一个待处理的请求,要为我编写的温度日志应用程序编写报告,但我似乎无法确定查询。
应用程序存储温度日志。这些日志每天要在几个不同的地点进行 3 次。每个日志包含一个或多个区域,其中包含一个或多个设备。
我的报告需要显示在给定报告日期范围内连续超过 3 个记录周期出现温度不佳的设备 (EquipmentStoreID)。我还需要显示 "island" 或恶劣天气开始和结束的日期范围。一些注意事项:
- 如果错过了一个时间段,应该算是温度不好了。但是,"island" 失败的临时工不应从错过的日志开始。
- 可以在给定时间段内在同一位置完成多个日志,在这种情况下,好的温度会胜过任何坏的。
这是我的SQLFiddle。我的结果不正确,因为连续失败从实际错过的时间段开始,我不知道如何处理同一时间段的多个日志。
非常感谢任何帮助!
这是我想出的。
为了避免在丢失的日志上启动孤岛,我将行的日期与我们在每个商店看到的第一个记录日期(下面查询中的 minlog)进行了比较。如果该行的日期早于第一个日志日期,那么我们就知道它发生在我们开始记录之前,我不会用错误标志标记它。
为了在同一时间段处理多个日志,我在 StagedRows 中添加了一个 Priority 字段,我们可以使用它只抓取每个 Store/Datetime 的第一个条目,优先处理成功的日志。
WITH TargetLogs
AS (SELECT le.*,
CONVERT(DATETIME, CONVERT(DATE, lh.StartDateTime)) as Date,
lh.TimePeriodID,
lh.StartDateTime
FROM [dbo].[LogEquipment] le
JOIN [dbo].[LogArea] la
ON le.LogAreaID = la.LogAreaID
JOIN [dbo].[LogHeader] lh
ON lh.LogHeaderID = la.LogHeaderID
WHERE lh.StartDateTime Between CAST('2015-01-14' AS DateTime)
AND CAST('2015-01-16' AS DateTime)
),
Dates --Generate date range
AS (SELECT CAST('2015-01-14' AS DateTime) 'date'
UNION ALL
SELECT Dateadd(dd, 1, t.date)
FROM Dates t
WHERE Dateadd(dd, 1, t.date) <= CAST('2015-01-16' AS DateTime)),
DesiredDatesAndTimePeriods --Generate datetimes for all timeperiods between date range
AS (SELECT DISTINCT tp.TimePeriodID,
tp.TimeDescription,
tp.StartTime,
d.Date,
d.Date + CONVERT(DATETIME, tp.StartTime) AS LogStartDateTime,
le.EquipmentStoreID
FROM dbo.TimePeriod tp
CROSS JOIN Dates d
CROSS JOIN LogEquipment le
WHERE tp.IsActive = 1),
StagedRows
AS (SELECT * FROM
(
SELECT d.LogStartDateTime,
d.EquipmentStoreID,
t.LogEquipmentID,
t.CorrectiveAction,
CASE WHEN minlog.MinStartDateTime <= d.LogStartDateTime
AND (t.LogEquipmentID IS NULL OR CorrectiveAction IS NOT NULL)
THEN 1 ELSE 0 END AS FailedFlag,
ROW_NUMBER() OVER (PARTITION BY d.Date, d.TimePeriodID
ORDER BY CASE WHEN CorrectiveAction IS NULL THEN 0 ELSE 1 END)
AS Priority
FROM DesiredDatesAndTimePeriods d
LEFT OUTER JOIN TargetLogs t
on d.Date = t.Date AND d.TimePeriodId = t.TimePeriodId
LEFT OUTER JOIN (SELECT EquipmentStoreId, MIN(StartDateTime) as MinStartDateTime FROM TargetLogs GROUP BY EquipmentStoreId) minlog
on d.EquipmentStoreID = minlog.EquipmentStoreID
) dt WHERE Priority = 1)
SELECT EquipmentStoreID,
Count(*) AS ConsecutiveFails,
Start_date = Min(LogStartDateTime),
Stop_date = Max(LogStartDateTime)
FROM (SELECT EquipmentStoreID,
FailedFlag,
LogStartDateTime,
ROW_NUMBER()
OVER (
ORDER BY EquipmentStoreID, LogStartDateTime) - ROW_NUMBER()
OVER (
PARTITION BY EquipmentStoreID, FailedFlag
ORDER BY EquipmentStoreID, LogStartDateTime)
grp
FROM StagedRows) A
GROUP BY EquipmentStoreID, FailedFlag,
grp
HAVING FailedFlag = 1
AND Count(*) > 3
ORDER BY Min(LogStartDateTime)
我有一个待处理的请求,要为我编写的温度日志应用程序编写报告,但我似乎无法确定查询。
应用程序存储温度日志。这些日志每天要在几个不同的地点进行 3 次。每个日志包含一个或多个区域,其中包含一个或多个设备。
我的报告需要显示在给定报告日期范围内连续超过 3 个记录周期出现温度不佳的设备 (EquipmentStoreID)。我还需要显示 "island" 或恶劣天气开始和结束的日期范围。一些注意事项:
- 如果错过了一个时间段,应该算是温度不好了。但是,"island" 失败的临时工不应从错过的日志开始。
- 可以在给定时间段内在同一位置完成多个日志,在这种情况下,好的温度会胜过任何坏的。
这是我的SQLFiddle。我的结果不正确,因为连续失败从实际错过的时间段开始,我不知道如何处理同一时间段的多个日志。
非常感谢任何帮助!
这是我想出的。
为了避免在丢失的日志上启动孤岛,我将行的日期与我们在每个商店看到的第一个记录日期(下面查询中的 minlog)进行了比较。如果该行的日期早于第一个日志日期,那么我们就知道它发生在我们开始记录之前,我不会用错误标志标记它。
为了在同一时间段处理多个日志,我在 StagedRows 中添加了一个 Priority 字段,我们可以使用它只抓取每个 Store/Datetime 的第一个条目,优先处理成功的日志。
WITH TargetLogs
AS (SELECT le.*,
CONVERT(DATETIME, CONVERT(DATE, lh.StartDateTime)) as Date,
lh.TimePeriodID,
lh.StartDateTime
FROM [dbo].[LogEquipment] le
JOIN [dbo].[LogArea] la
ON le.LogAreaID = la.LogAreaID
JOIN [dbo].[LogHeader] lh
ON lh.LogHeaderID = la.LogHeaderID
WHERE lh.StartDateTime Between CAST('2015-01-14' AS DateTime)
AND CAST('2015-01-16' AS DateTime)
),
Dates --Generate date range
AS (SELECT CAST('2015-01-14' AS DateTime) 'date'
UNION ALL
SELECT Dateadd(dd, 1, t.date)
FROM Dates t
WHERE Dateadd(dd, 1, t.date) <= CAST('2015-01-16' AS DateTime)),
DesiredDatesAndTimePeriods --Generate datetimes for all timeperiods between date range
AS (SELECT DISTINCT tp.TimePeriodID,
tp.TimeDescription,
tp.StartTime,
d.Date,
d.Date + CONVERT(DATETIME, tp.StartTime) AS LogStartDateTime,
le.EquipmentStoreID
FROM dbo.TimePeriod tp
CROSS JOIN Dates d
CROSS JOIN LogEquipment le
WHERE tp.IsActive = 1),
StagedRows
AS (SELECT * FROM
(
SELECT d.LogStartDateTime,
d.EquipmentStoreID,
t.LogEquipmentID,
t.CorrectiveAction,
CASE WHEN minlog.MinStartDateTime <= d.LogStartDateTime
AND (t.LogEquipmentID IS NULL OR CorrectiveAction IS NOT NULL)
THEN 1 ELSE 0 END AS FailedFlag,
ROW_NUMBER() OVER (PARTITION BY d.Date, d.TimePeriodID
ORDER BY CASE WHEN CorrectiveAction IS NULL THEN 0 ELSE 1 END)
AS Priority
FROM DesiredDatesAndTimePeriods d
LEFT OUTER JOIN TargetLogs t
on d.Date = t.Date AND d.TimePeriodId = t.TimePeriodId
LEFT OUTER JOIN (SELECT EquipmentStoreId, MIN(StartDateTime) as MinStartDateTime FROM TargetLogs GROUP BY EquipmentStoreId) minlog
on d.EquipmentStoreID = minlog.EquipmentStoreID
) dt WHERE Priority = 1)
SELECT EquipmentStoreID,
Count(*) AS ConsecutiveFails,
Start_date = Min(LogStartDateTime),
Stop_date = Max(LogStartDateTime)
FROM (SELECT EquipmentStoreID,
FailedFlag,
LogStartDateTime,
ROW_NUMBER()
OVER (
ORDER BY EquipmentStoreID, LogStartDateTime) - ROW_NUMBER()
OVER (
PARTITION BY EquipmentStoreID, FailedFlag
ORDER BY EquipmentStoreID, LogStartDateTime)
grp
FROM StagedRows) A
GROUP BY EquipmentStoreID, FailedFlag,
grp
HAVING FailedFlag = 1
AND Count(*) > 3
ORDER BY Min(LogStartDateTime)