我有中级 SQL 技能,但这是我尝试过的最复杂的查询。
我的目标是构建一个查询,显示任何一天中有多少分钟,一组 6 个驱动器正在使用或空闲。“正在使用”的驱动器正在将备份写入磁带,也就是运行作业。驱动器一次只能处理工作。驱动器可以在同一天开始和结束一项工作,或者如果它是一项大工作,则可以在一天开始并在 2 天后结束。最重要的是,我能够报告每个驱动器处于 UP 或 IDLE 的分钟数(两者都很重要),并且即使工作进行到下一天,也只报告它在相应一天工作的分钟数。
因此,复杂性源于以下
我不能只从结束时间中减去开始时间,然后对特定驱动器运行的所有作业的经过时间求和,因为许多作业跨越午夜,我必须将工作分钟数分配给它们发生的那一天。IE。我不能报告驱动器在 24 小时内完成了 50 小时的工作,仅仅因为工作的结束时间是 2 天。
开始时间和结束时间列采用 UTC 时间,必须转换为 PST。
当任何一个驱动器空闲时,我需要占位符,以便我可以显示每个驱动器的启动/空闲时间。
我需要放在一起的表只有两个:
时间日历表。从 2009 年 10 月 10 日到 2021 年 7 月 10 日,一天中的每一分钟都有一行。
包含所有已完成作业的开始和结束时间、运行它们的驱动器名称以及作业名称的表。
这是DDL
一个日历表,其中包含从 2009 年到 2014 年一天中每一分钟的一行。
WITH e1(min) AS(
SELECT * FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))x(n)
),
e2(min) AS(
SELECT e1.min FROM e1, e1 x
),
e4(min) AS(
SELECT e2.min FROM e2, e2 x
),
e8(min) AS(
SELECT e4.min FROM e4, e4 x
),
cteTally(min) AS(
SELECT TOP 6307204 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1
FROM e8
),
Test(min) AS(
SELECT DATEADD( minute, min, DATEADD( YEAR, -2, GETDATE()))
FROM cteTally)
SELECT DATEADD( MINUTE, DATEDIFF( MINUTE, 0, DATEADD( YEAR, -2, GETDATE())), 0)
FROM Test
WHERE min <= DATEADD( YEAR, 10, GETDATE())
这是包含设备/作业/开始和结束时间的表的示例 DDL。
CREATE TABLE JobHistorySummary
(JobName nvarchar(255),
ActualStartTime datetime,
EndTime datetime,
DeviceName nvarchar(128))
INSERT INTO JobHistorySummary
VALUES
('FOAMTools E: Weekly - FULL', '2013-08-04 03:20:00.000', '2013-08-04 20:20:00.000', '1 Drv'),
('HRDuplex D: Weekly - FULL', '2013-08-04 18:26:00.000', '2013-08-05 13:00:00.000', '2 Drv'),
('HRDuplex D: Daily - INC', '2013-08-04 20:44:00.000', '2013-08-05 15:50:00.000', '1 Drv'),
('PayNROLL C: Weekly - FULL', '2013-08-04 00:00:00.000', '2013-08-06 15:40:00.000','3 Drv'),
('PayNROLL C: Daily - INC', '2013-08-05 06:30:00.000', '2013-08-05 06:50:00.000', '4 Drv'),
('SmallIBM F: Daily - FULL', '2013-08-04 00:30:00.000', '2013-08-04 06:30:00.000', '5 Drv'),
('BigIBM F: Daily - INC', '2013-08-06 12:30:00.000', '2013-08-06 12:50:00.000', '6 Drv');
需要获取本地时间的计算是 [ActualStartTime]+ GETDATE() - GETUTCDATE())
即使我只需要两个表,我也无法弄清楚加入它们的逻辑,以便它们为驱动器空闲的那些日期时间创建 NULL 占位符。我想将具有 NULL 值的行计数为每个驱动器的空闲分钟数。此外,我无法弄清楚如何将使用分钟数与它们发生的那一天隔离开来……这意味着每个驱动器每天的工作时间不超过 1440 分钟,即使对于跨越午夜的工作也是如此。次日的分钟数被分配为由各自的驱动器工作到次日的分钟数。