[英]SQL: Reporting on data by date
我有一张正在尝试从中生成报告的表格。 它基本上是什么时候发生故障(崩溃)然后修复的日志。
表架构和一些示例数据如下。 为了显示:
下降时插入1行
备份时插入1行。
我想做的是报告各个方面,例如:
给定日期/星期/月的停机时间
在给定的日期/星期/月中发生故障的次数。
理想情况下,可以轻松导出为excel或类似图形的方式。
我无法提出任何查询来获取此信息。
我有一个这样的例子:
SELECT [Name], datepart(day,[Inserted]), count([SystemDown])
FROM [DownTimeLog]
WHERE [SystemDown]=1
GROUP BY [Name],datepart(day,[Inserted])
这给了我每天系统出现故障的次数,这是一个很好的起点。
但是我试图提出一种显示总时间下降的方法,但我正在空白。 例如,有些日子可能是0,有时可能会下降几次,因此尝试求和2个对应行之间的时间差是很困难的。
CREATE TABLE [dbo].[DownTimeLog]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] VARCHAR(30) NOT NULL,
[SystemDown] BIT NOT NULL,
[Inserted] DATETIME NOT NULL
)
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 14 2011 1:49:58:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 14 2011 2:49:58:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 15 2011 1:00:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 15 2011 2:00:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 15 2011 4:00:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 15 2011 5:00:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 17 2011 1:00:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 17 2011 3:00:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 18 2011 10:00:00:000AM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 18 2011 11:00:00:000AM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 18 2011 1:00:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 18 2011 3:30:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 18 2011 4:00:00:000PM')
INSERT INTO [DownTimeLog] ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 18 2011 8:00:00:000PM')
因此,例如,使用上面的数据,我想将数据拉回去,就像这样:
系统1 | 2011年6月14日| 1小时 1次发生
系统1 | 2011年6月15日| 2小时 2次发生
系统1 | 2011年6月16日| 0小时| 0次发生
系统1 | 2011年6月17日| 2小时 1次发生
系统1 | 2011年6月18日| 7.5小时| 3次发生
我希望有人可以给我一种方法来做我想做的事情。
-编辑:
谢谢大家的出色回答。 帮了我一吨。 我以为我的sql很漂亮,虽然从来没有听说过交叉应用-猜猜我需要回到学校!
干杯!
我认为,如果将它们分成两个伪表,您将可以做更多的事情。 尝试这个:
SELECT
*
FROM
( SELECT
*
FROM
[DownTimeLog] AS down
WHERE
[SystemDown] = 1
) down
INNER JOIN ( SELECT
*
FROM
[DownTimeLog]
WHERE
SystemDown = 0
) up
ON down.id = ( up.id - 1 ) and down.name = up.name
ORDER BY down.[Inserted], up.inserted
然后,您可以对down
记录和后续up
记录进行各种计算。
编辑:当然,@ Dems指出这是假定ID是连续的。 如果您希望使用日期作为过滤器,请执行以下操作:
SELECT
*
FROM
( SELECT
*
FROM
[DownTimeLog] AS down
WHERE
[SystemDown] = 1
) down
CROSS APPLY ( SELECT TOP 1
*
FROM
[DownTimeLog] up
WHERE
SystemDown = 0
AND up.INSERTED > down.INSERTED
AND up.NAME = down.name
ORDER BY up.inserted
) up
ORDER BY down.[Inserted], up.inserted
这是可以做什么的更详细的示例:
SELECT
[Down_Id]
, [Down_Name]
, [Down_SystemDown]
, [Down_Inserted]
, [Up_Id]
, [Up_Name]
, [Up_SystemDown]
, [Up_Inserted]
, CAST(DATEDIFF(mi,Down_Inserted,Up_Inserted) AS DECIMAL)/60 AS Hours_Down
, DATEDIFF(mi,Down_Inserted,Up_Inserted) AS Minutes_Down
FROM
( SELECT
[ID] AS Down_Id
, [Name] AS Down_Name
, [SystemDown] AS Down_SystemDown
, [Inserted] AS Down_Inserted
FROM
[DownTimeLog] AS down
WHERE
[SystemDown] = 1
) down
CROSS APPLY ( SELECT TOP 1
[ID] AS Up_Id
, [Name] AS Up_Name
, [SystemDown] AS Up_SystemDown
, [Inserted] AS Up_Inserted
FROM
[DownTimeLog] up
WHERE
SystemDown = 0
AND up.[Inserted] > down.Down_Inserted
AND up.NAME = down.Down_name
ORDER BY
up.Inserted
) up
ORDER BY
down.[Down_Inserted]
, up.up_inserted
这样的事情可能适合您。
select D1.Name,
dateadd(d, datediff(d, 0, D1.Inserted), 0) as [Date],
sum(datediff(mi, D1.Inserted, D2.Inserted)) as DownTime,
count(*) as Occurrences
from DownTimeLog as D1
cross apply ( select top 1 Name,
Inserted
from DownTimeLog
where Name = D1.Name and
Inserted > D1.Inserted
order by Inserted
) as D2
where D1.SystemDown = 1
group by D1.Name, dateadd(d, datediff(d, 0, D1.Inserted), 0)
结果:
Name Date DownTime Occurrences
------------------------------ ----------------------- ----------- -----------
System1 2011-06-14 00:00:00.000 60 1
System1 2011-06-15 00:00:00.000 120 2
System1 2011-06-17 00:00:00.000 120 1
System1 2011-06-18 00:00:00.000 450 3
您不会连续几天出现0次。 如果您在午夜有停机时间,则所有时间都将计入停机事件当天。 停机时间以分钟为单位。
WITH
enhanced_log
AS
(
SELECT
[start].Name AS [Name],
DATEADD(DAY, DATEDIFF(DAY, 0, [start].Inserted), 0) AS [Date],
[start].Inserted AS [Start],
[finish].Inserted AS [Finish]
FROM
DownTimeLog AS [start]
OUTER APPLY
(SELECT TOP 1 * FROM DownTimeLog WHERE name = [start].name AND Inserted > [start].Inserted ORDER BY Inserted ASC) AS [finish]
WHERE
[start].SystemDown = 1
UNION ALL
SELECT
[start].Name,
[Calendar].date,
[Calendar].date,
[finish].Inserted
FROM
calendar
CROSS JOIN
system
CROSS APPLY
(SELECT TOP 1 * FROM DownTimeLog WHERE name = [system].name AND Inserted < [calendar].date ORDER BY Inserted ASC) AS [start]
OUTER APPLY
(SELECT TOP 1 * FROM DownTimeLog WHERE name = [system].name AND Inserted > [start].Inserted ORDER BY Inserted ASC) AS [finish]
WHERE
[start].SystemDown = 1
)
SELECT
Name,
Date,
SUM(DATEDIFF(MINUTE, Start, CASE WHEN Finish < Date + 1 THEN Finish ELSE Date + 1 END)) AS Duration,
COUNT(*) AS Instances
FROM
enhanced_log
WHERE
Start <> CASE WHEN Finish < Date + 1 THEN Finish ELSE Date + 1 END
GROUP BY
Name,
Date
以下将产生您的确切输出,包括缺少的日期。 请注意,此代码基于Mikael Eriksson的答案。
CREATE TABLE #DownTimeLog
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] VARCHAR(30) NOT NULL,
[SystemDown] BIT NOT NULL,
[Inserted] DATETIME NOT NULL
)
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 14 2011 1:49:58:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 14 2011 2:49:58:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 15 2011 1:00:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 15 2011 2:00:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 15 2011 4:00:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 15 2011 5:00:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 17 2011 1:00:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 17 2011 3:00:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 18 2011 10:00:00:000AM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 18 2011 11:00:00:000AM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 18 2011 1:00:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 18 2011 3:30:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',1,'Jun 18 2011 4:00:00:000PM')
INSERT INTO #DownTimeLog ([Name],[SystemDown],[Inserted])VALUES('System1',0,'Jun 18 2011 8:00:00:000PM')
CREATE TABLE #DownTimeLogModified (Name nvarchar(512), [Date] nvarchar(512), DownTime int, Occurrences int)
INSERT INTO #DownTimeLogModified (Name, [Date], DownTime, Occurrences)
select D1.Name,
CONVERT(VARCHAR(12), dateadd(d, datediff(d, 0, D1.Inserted), 0), 107) as [Date],
sum(datediff(mi, D1.Inserted, D2.Inserted)) as DownTime,
count(*) as Occurrences
from #DownTimeLog as D1
cross apply ( select top 1 Name,
Inserted
from #DownTimeLog
where SystemDown = 0 and
Name = D1.Name and
Inserted > D1.Inserted
order by Inserted
) as D2
where D1.SystemDown = 1
group by D1.Name, dateadd(d, datediff(d, 0, D1.Inserted), 0)
DECLARE @startdate datetime,@enddate datetime
select @startdate = MIN(Inserted) FROM #DownTimeLog
select @enddate = MAX(Inserted) FROM #DownTimeLog
;WITH DateIntervalsCTE AS
(
SELECT 1 i,@startdate AS Date
UNION ALL
SELECT i + 1, DATEADD(day, i, @startdate )
FROM DateIntervalsCTE
WHERE DATEADD(day, i, @startdate ) <= @enddate
)
SELECT CASE WHEN a.Name is null THEN 'No System downtime' ELSE a.Name END as Name,CONVERT(VARCHAR(12), b.Date, 107) AS Date,CASE WHEN a.DownTime is null THEN 0 ELSE a.DownTime END AS DownTime,CASE WHEN a.Occurrences is null THEN 0 ELSE a.Occurrences END AS Occurrences
FROM DateIntervalsCTE b
LEFT JOIN #DownTimeLogModified a ON a.Date = CONVERT(VARCHAR(12), b.Date, 107)
DROP TABLE #DownTimeLog
DROP TABLE #DownTimeLogModified
产量
Name Date DownTime Occurrences
------------------------------ ----------------------- ----------- -----------
System1 Jun 14, 2011 60 1
System1 Jun 15, 2011 120 2
No system downtime Jun 16, 2011 0 0
System1 Jun 17, 2011 120 1
System1 Jun 18, 2011 450 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.