长时间跟踪者,第一次海报(和SQL初学者)。我的问题类似于这个SQL to find time elapsed from multiple overlapping intervals,除了我能够使用CTE,UDF等,我正在寻找更多细节。
在一台大型设备上,我记录了所有出现的故障。系统的不同子组件可能出现故障,有些可能完全脱机(完全停机=是),而其他子组件则没有(完全停机=否)。故障可能会在时间上重叠,如果故障尚未修复,故障可能没有结束时间。
Outage_ID StartDateTime EndDateTime CompleteOutage
1 07:00 3-Jul-13 08:55 3-Jul13 Yes
2 08:30 3-Jul-13 10:00 4-Jul13 No
3 12:00 4-Jul-13 No
4 12:30 4-Jul13 12:35 4-Jul-13 No
1 |---------|
2 |---------|
3 |--------------------------------------------------------------
4 |---|
我需要能够在用户定义的时间段内完成工作,整个系统完全正常运行多长时间(无故障),退化多长时间(一个或多个非完全中断)以及无法运行多长时间(一个或更完整的中断)。我还需要能够在任何给定的时间段内解决系统中出现的故障。我想在打开或关闭故障的任何时候创建一个“Stage Change”表,但我仍然坚持这样做的最佳方式 - 对这个或更好的解决方案的任何帮助都将不胜感激!
答案 0 :(得分:2)
这不是一个完整的解决方案(我将其留作练习:))但应该说明基本技术。诀窍是创建一个状态表(如你所说)。如果您为"开始"事件和-1为"结束"事件然后事件日期/时间顺序中的运行总计为您提供该特定事件日期/时间的当前状态。下面的SQL是T-SQL,但应该很容易适应您正在使用的任何数据库服务器。
以部分中断数据为例:
DECLARE @Faults TABLE (
StartDateTime DATETIME NOT NULL,
EndDateTime DATETIME NULL
)
INSERT INTO @Faults (StartDateTime, EndDateTime)
SELECT '2013-07-03 08:30', '2013-07-04 10:00'
UNION ALL SELECT '2013-07-04 12:00', NULL
UNION ALL SELECT '2013-07-04 12:30', '2013-07-04 12:35'
-- "Unpivot" the events and assign 1 to a start and -1 to an end
;WITH FaultEvents AS (
SELECT *, Ord = ROW_NUMBER() OVER(ORDER BY EventDateTime)
FROM (
SELECT EventDateTime = StartDateTime, Evt = 1
FROM @Faults
UNION ALL SELECT EndDateTime, Evt = -1
FROM @Faults
WHERE EndDateTime IS NOT NULL
) X
)
-- Running total of Evt gives the current state at each date/time point
, FaultEventStates AS (
SELECT A.Ord, A.EventDateTime, A.Evt, [State] = (SELECT SUM(B.Evt) FROM FaultEvents B WHERE B.Ord <= A.Ord)
FROM FaultEvents A
)
SELECT StartDateTime = S.EventDateTime, EndDateTime = F.EventDateTime
FROM FaultEventStates S
OUTER APPLY (
-- Find the nearest transition to the no-fault state
SELECT TOP 1 *
FROM FaultEventStates B
WHERE B.[State] = 0
AND B.Ord > S.Ord
ORDER BY B.Ord
) F
-- Restrict to start events transitioning from the no-fault state
WHERE S.Evt = 1 AND S.[State] = 1
如果您使用的是SQL Server 2012,则可以选择使用windowing function计算运行总计。
答案 1 :(得分:1)
以下是实现此工作的粗略指南。它将与日期间隔表和15分钟的间隔表进行比较。然后它会将中断事件(每个间隔1个事件)相加,但如果完全中断则不会将部分中断加起来。
如果需要,您可以使用更精细的时间间隔,我选择15分钟来提高编码速度。
我已经设置了日期间隔表“CAL.t_Calendar”,因此您需要创建自己的一个来运行此代码。
请注意,这并不代表您应该使用的实际代码。它只是作为一个演示,并指出你可能的方向......
编辑我刚刚意识到我没有考虑到空结束日期。代码将需要修改以检查NULL endDates并使用@EndDate或GETDATE()如果@EndDate是将来
--drop table ##Events
CREATE TABLE #Events (OUTAGE_ID INT IDENTITY(1,1) PRIMARY KEY
,StartDateTime datetime
,EndDateTime datetime
, completeOutage bit)
INSERT INTO #Events VALUES ('2013-07-03 07:00','2013-07-03 08:55',1),('2013-07-03 08:30','2013-07-04 10:00',0)
,('2013-07-04 12:00',NULL,0),('2013-07-04 12:30','2013-07-04 12:35',0)
--drop table #FiveMins
CREATE TABLE #FiveMins (ID int IDENTITY(1,1) PRIMARY KEY, TimeInterval Time)
DECLARE @Time INT = 0
WHILE @Time <= 1410 --number of 15 min intervals in day * 15
BEGIN
INSERT INTO #FiveMins SELECT DATEADD(MINUTE , @Time, '00:00')
SET @Time = @Time + 15
END
SELECT * from #FiveMins
DECLARE @StartDate DATETIME = '2013-07-03'
DECLARE @EndDate DATETIME = '2013-07-04 23:59:59.999'
SELECT SUM(FullOutage) * 15 as MinutesFullOutage
,SUM(PartialOutage) * 15 as MinutesPartialOutage
,SUM(NoOutage) * 15 as MinutesNoOutage
FROM
(
SELECT DateAnc.EventDateTime
, CASE WHEN COUNT(OU.OUTAGE_ID) > 0 THEN 1 ELSE 0 END AS FullOutage
, CASE WHEN COUNT(OU.OUTAGE_ID) = 0 AND COUNT(pOU.OUTAGE_ID) > 0 THEN 1 ELSE 0 END AS PartialOutage
, CASE WHEN COUNT(OU.OUTAGE_ID) > 0 OR COUNT(pOU.OUTAGE_ID) > 0 THEN 0 ELSE 1 END AS NoOutage
FROM
(
SELECT CAL.calDate + MI.TimeInterval AS EventDateTime
FROM CAL.t_Calendar CAL
CROSS JOIN #FiveMins MI
WHERE CAL.calDate BETWEEN @StartDate AND @EndDate
) DateAnc
LEFT JOIN #Events OU
ON DateAnc.EventDateTime BETWEEN OU.StartDateTime AND OU.EndDateTime
AND OU.completeOutage = 1
LEFT JOIN #Events pOU
ON DateAnc.EventDateTime BETWEEN pOU.StartDateTime AND pOU.EndDateTime
AND pOU.completeOutage = 0
GROUP BY DateAnc.EventDateTime
) AllOutages