提问人:Rhodney Noquiao 提问时间:11/18/2023 最后编辑:Thom ARhodney Noquiao 更新时间:11/18/2023 访问量:46
如果处理时间在班次计划范围内,则可以计算和检查处理时间的查询 [已关闭]
query that can count and check process time if it is in shift schedule range [closed]
问:
我有 2 张表,第一张表
有,第二张表有
,还有 。startprocesstime
endprocesstime
EmployeeID
StartShift
EndShift
我需要检查 和 是否仍然在我的 .startprocesstime
Endprocesstime
shiftschedule
示例: 方案 1:Startprocesstime Endprocessime 方案 2:Startprocesstime Endprocessime 2023-11-18 4:30:000
2023-11-18 4:31:000
2023-11-19 00:30:000
2023-11-19 00:31:000
EmployeedID 4pm(StartShift) to 1am(EndShift).
答:
一种方法是将流程与班次交叉联接,然后在每个流程涵盖的所有日期复制班次。请注意,如果第一个候选班次超过午夜,则该班次可能在流程开始的前一天开始。
然后,可以使用标准测试检查过程和班次日期/时间范围是否重叠。对于每个重叠,重叠量(以分钟为单位)可以计算为 。start1 < end2 AND start2 < end1
DATEDIFF(minute, GREATEST(start1, start2), LEAST(end1, end2))
最后,由于在多天内可能存在多个具有相同流程/班次组合的结果,因此可用于将它们组合起来并应用于计算重叠的总和。GROUP BY
SUM()
生成的查询将如下所示:
SELECT
P.Name AS PName
,CONVERT(SMALLDATETIME, P.Start) AS PStart
,CONVERT(SMALLDATETIME, P.Finish) AS PFinish
,SUM(DATEDIFF(minute, GREATEST(P.Start, SS.Start), LEAST(P.Finish, SS.Finish))) AS Minutes
,S.Name AS SName
,CONVERT(CHAR(5), S.Start, 8) AS SStart
,CONVERT(CHAR(5), S.Finish, 8) AS SFinish
FROM (
-- Process data plus some calculated fields
SELECT
P.*,
CONVERT(DATE, P.Start) AS StartDate,
DATEDIFF(day, P.Start, P.Finish) AS Days
FROM Process P
) P
CROSS JOIN (
-- Shift data plus a check for midnight crossover
SELECT
S.*,
CASE WHEN S.Start > S.Finish THEN 1 ELSE 0 END AS CrossOver
FROM Shift S
) S
CROSS APPLY (
-- Replicate shifts across all dates covered by each process
SELECT
CONVERT(DATETIME, DATEADD(day, G.value, P.StartDate)) + CONVERT(DATETIME, S.Start) AS Start,
CONVERT(DATETIME, DATEADD(day, G.value + S.Crossover, P.StartDate)) + CONVERT(DATETIME, S.Finish) AS Finish
FROM GENERATE_SERIES(-S.Crossover, P.Days) G
) SS
WHERE (P.Start < SS.Finish AND SS.Start < P.Finish) -- overlap test
GROUP BY
P.Name, P.Start, P.Finish
,S.Name, S.Start, S.Finish
ORDER BY P.Name, S.Name
示例结果(带有一些额外的测试数据):
PName | PStart的 | PFinish | 纪要 | SName的 | SStart(英语:SStart) | SFinish |
---|---|---|---|---|---|---|
流程 1 | 2023-11-18 04:30 | 2023-11-18 04:31 | 1 | 班次 2 | 23:00 | 07:00 |
流程 2 | 2023-11-19 00:30 | 2023-11-19 00:31 | 1 | 班次 1 | 16:00 | 01:00 |
流程 2 | 2023-11-19 00:30 | 2023-11-19 00:31 | 1 | 班次 2 | 23:00 | 07:00 |
流程 3 | 2023-11-22 23:45 | 2023-11-23 00:15 | 30 | 班次 1 | 16:00 | 01:00 |
流程 3 | 2023-11-22 23:45 | 2023-11-23 00:15 | 30 | 班次 2 | 23:00 | 07:00 |
流程 4 | 2023-11-24 23:45 | 2023-11-27 00:15 | 1110 | 班次 1 | 16:00 | 01:00 |
流程 4 | 2023-11-24 23:45 | 2023-11-27 00:15 | 990 | 班次 2 | 23:00 | 07:00 |
流程 4 | 2023-11-24 23:45 | 2023-11-27 00:15 | 120 | 班次 3 | 01:00 | 02:00 |
流程 4 | 2023-11-24 23:45 | 2023-11-27 00:15 | 1080 | 班次 4 | 07:00 | 16:00 |
流程 4 | 2023-11-24 23:45 | 2023-11-27 00:15 | 1080 | 换档 5 | 12:00 | 21:00 |
请注意,源数据仅限于原始 OP 发布数据中的 Shift 1 和 Process 1 和 Process 2,只有 1 分钟重叠的匹配项。
请参阅此 db<>fiddle。
我还尝试了一种不同的方法,在所有午夜交叉时将班次和过程日期/时间范围分开,并减少到仅时间范围。虽然取得了相同的结果,但代码更加复杂。我没有在这里发布该来源,但已将其包含在上述小提琴的末尾。
上面的代码使用 SQL Server 2022 中新增的 、 和 函数。如果您使用的是旧版本,则需要替换替换。 并且可以替换为表达式。至于,那会更复杂......LEAST()
GREATEST()
GENERATE_SERIES()
LEAST()
GREATEST()
CASE
GENERATE_SERIES()
-- GREATEST(P.Start, SS.Start) replacement
CASE WHEN P.Start > SS.Start THEN P.Start ELSE SS.Start END
-- LEAST(P.Finish, SS.Finish) replacement
CASE WHEN P.Finish < SS.Finish THEN P.Finish ELSE SS.Finish
-- GENERATE_SERIES(-S.Crossover, P.Days) replacement
FROM (
SELECT TOP (P.Days + S.Crossover + 1)
-1 - S.Crossover + ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Value
FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) A(N)
CROSS JOIN (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) B(N)
CROSS JOIN (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) C(N)
) G
请参阅此 db<>fiddle,了解使用较旧版本的 SQL Server 运行的代码。
评论
start1 < end2 AND start2 < end1
startprocesstime < EndShift AND StartShift < endprocesstime