我正在尝试从服务记录计算列车的停机时间,下面是一个示例场景
可以有多个同时运行的作业可以有时重叠
对于:
-
Job_number 1 工作开始日期和结束日期之间的日期差异为360分钟
-
Job_number 2 工作开始日期和结束日期之间的日期差异是60分钟,但这与Job_number 1重叠,所以我们不应该考虑这个
-
Job_number 3 工作开始日期和结束日期之间的日期差异是45分钟,但这部分与Job_number 1重叠,所以我们应该只考虑10分钟
因此实际停机时间应为360分钟(作业1)0分钟(作业2)10分钟(作业3)= 370 Minute
我想要的输出是: -
我现在有20列火车,我需要按照上面的计算来计算停机时间
我该怎么做呢?
示例数据脚本:
CREATE TABLE [dbo].[tb_ServiceMemo](
[Job_Number] [nvarchar](500) NULL,
[Train_Number] [nvarchar](500) NULL,
[Work_Start_Date] [datetime] NULL,
[Work_Completed_Date] [datetime] NULL
) ON [PRIMARY]
INSERT INTO [dbo].[tb_ServiceMemo]
VALUES (1,1,'01-08-2018 12:35','01-08-18 18:35'),
(2,1,'01-08-2018 14:20','01-08-18 15:20'),
(3,1,'01-08-2018 18:00','01-08-18 18:45')
4 回答
你能试试这个吗?我添加了其他测试用例,但我认为没关系 . 我也觉得还有更简单
这个想法是:
忽略包含在另一个中的结果
如果她被包含在另一个中,则重写每个rown的开始日期值
这是序列中的间隙和岛屿问题 .
您可以尝试使用递归CTE,在每一行中获取分钟 . 然后使用每个
MAX
和MIN
DateTime来计算结果 .sqlfiddle
这是一个间隙和岛屿问题,但它很棘手,因为它有开始和结束时间 .
解决方案的想法是确定中断何时开始 . 有什么特点?那么,期间开始于与之前工作没有重叠的时期 . 棘手的部分是,可以同时启动多个“工作”工作(尽管您的数据没有显示这一点) .
一旦知道中断开始的时间,就可以使用累积总和为每个记录分配一个组,然后简单地按该组(以及其他信息)进行聚合 .
以下查询应该执行您想要的操作:
在这个db<>fiddle中,我添加了几行来展示代码在不同场景中的工作方式 .
这是与日期有关的臭名昭着的空白和岛屿问题 . 以下是使用递归CTE的解决方案 . 如果您不习惯与他们合作可能有点难以理解,我评论了可能需要澄清的所有部分 .
我还添加了一些示例来考虑不同的场景,例如不同的时段天数和完全在开始/结束时的重叠时间 .
示例设置:
解决方案:
这些是每个CTE的部分结果,因此您可以看到每个步骤:
TimeLapses :
MaxRecursionLevelByTrain :
ExtendedLapses :
Final Result :
一些值得一提的事情:
虽然这个解决方案肯定比使用游标更快,但它可能不是最好的解决方案,特别是如果你有一个庞大的数据集(超过10万条记录) . 有改善表现的空间 .
您可能会受益于
#tb_ServiceMemo
(Train_Number, Job_Number, Work_Start_Date
)上的索引以加快查询速度 .您可能需要在
SELECT
语句的末尾添加OPTION (MAXRECURSION N)
,N
是您要尝试的最大递归级别 . 默认值为100
,因此如果特定列车的链接数超过100个,则会弹出错误消息 . 您可以使用0
作为N
无限制 .确保每个结束时间都高于开始时间,并且作业编号不会重复,至少每列火车都要重复 .