我有中级SQL技能,但这是我尝试过的最复杂的查询。
我的目标是构建一个查询,显示任何给定日期的分钟数,一组6个驱动器正在使用或空闲。 “正在使用”的驱动器正在将备份写入磁带,即运行作业。驱动器一次只能处理作业。如果这是一项大工作,驱动器可以在同一天开始和结束工作,或者从一天开始并在两天后结束。最重要的是,我能够报告每个驱动器是UP或IDLE(两者都很重要)的分钟数,并且只报告它在相应日期工作的分钟数,即使工作进入下一个。
因此,复杂性来自以下
我不能简单地从结束时间中减去开始时间并将特定驱动器运行的所有作业的已用时间相加,因为许多工作都在午夜,我必须将工作时间分配给他们工作的那一天。发生了。 IE浏览器。我无法报告驱动器在24小时内执行了50小时的工作,只是因为工作的结束时间是2天。
开始时间和结束时间列均为UTC时间,必须转换为PST。
当任何一个驱动器处于空闲状态时,我需要几分钟的占位符,以便我可以显示每个驱动器的空闲时间。
我需要整理的表格只有两个:
时间日历表。从10-10-2009到10-07-2021,每天每分钟都有一排。
一个表,其中包含已完成的所有作业的开始和结束时间,运行它们的驱动器的名称以及作业的名称。
这是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分钟,即使是跨越午夜的工作。第二天的分钟被分配为相应的驱动器在第二天工作的分钟数。
答案 0 :(得分:0)
以下显示如何生成每台设备每天的使用时间。空闲时间仅为24减去。假设您已生成一个包含表格范围内所有日期的表格,让我们使用一个Date类型的字段dt调用该cal。 (容易做到)。以下给出了一般方法。
select devicename, cal.dt, sum(time(least(actualendtime, cal.dt)- time(actualstarttime))
from JobHistorySummary jhs inner join cal
on (jhs.actualstarttime >= cal.dt and jhs.actualendtime < cal.dt)
group by devicename, cal.dt
现在您使用转换的时间使用上面的相同语句,并假设cal在转换的时区中。
select devicename, cal.dt, sum(time(least(convert_tz(actualendtime,'UTC','US/Pacific'), cal.dt)- time(convert_tz(actualstarttime,'UTC','US/Pacific')))
from JobHistorySummary jhs inner join cal
on (convert_tz(actualstarttime,'UTC','US/Pacific') >= cal.dt and convert_tz(actualendtime,'UTC','US/Pacific') < cal.dt)
group by devicename, cal.dt
但是上面也不是正确的,因为mysql没有对时间值进行减法和聚合求和。所以你需要使用更像的东西:
select devicename, cal.dt, econd_to_time(sum(time_to_second(timediff(time(least(actualendtime, cal.dt), time(actualstarttime)))))
from JobHistorySummary jhs inner join cal
on (jhs.actualstarttime >= cal.dt and jhs.actualendtime < cal.dt)
group by devicename, cal.dt