如果处理时间在班次计划范围内,则可以计算和检查处理时间的查询 [已关闭]

query that can count and check process time if it is in shift schedule range [closed]

提问人:Rhodney Noquiao 提问时间:11/18/2023 最后编辑:Thom ARhodney Noquiao 更新时间:11/18/2023 访问量:46

问:


想改进这个问题吗?通过编辑这篇文章添加详细信息并澄清问题。

昨天关闭。

我有 2 张表,第一张表
有,第二张表有
,还有 。
startprocesstimeendprocesstimeEmployeeIDStartShiftEndShift

我需要检查 和 是否仍然在我的 .startprocesstimeEndprocesstimeshiftschedule

示例: 方案 1:Startprocesstime Endprocessime 方案 2:Startprocesstime Endprocessime
2023-11-18 4:30:0002023-11-18 4:31:0002023-11-19 00:30:0002023-11-19 00:31:000

EmployeedID  4pm(StartShift) to 1am(EndShift).
sql-server 计数 日期添加

评论

0赞 Jens 11/18/2023
MySQL 或 (MS) sql-server。删除不相关的标签。
0赞 T N 11/18/2023
检查日期范围是否重叠的标准方法是 。在你的情况下,将是.您需要先将班次转换为日期/时间值。start1 < end2 AND start2 < end1startprocesstime < EndShift AND StartShift < endprocesstime
0赞 Rhodney Noquiao 11/18/2023
我使用了MSSQL@Jens。
0赞 T N 11/18/2023
这实际上是一个比我最初想象的更具挑战性的问题 - 将线性过程日期/时间范围与循环移位时间范围进行比较,两者都可能具有午夜交叉。我最初的想法是在任何午夜交叉点将班次和过程范围分解为一个或多个段,然后进行多对多比较。问题是:有没有一种更直接的比较方式,不涉及大量的和/或条件或案例陈述?
0赞 user3112728 11/18/2023
如果记录的工作在他们的班次之外,您想怎么做?很容易检查记录的窗口是否与班次开始或结束重叠。

答:

0赞 T N 11/18/2023 #1

一种方法是将流程与班次交叉联接,然后在每个流程涵盖的所有日期复制班次。请注意,如果第一个候选班次超过午夜,则该班次可能在流程开始的前一天开始。

然后,可以使用标准测试检查过程和班次日期/时间范围是否重叠。对于每个重叠,重叠量(以分钟为单位)可以计算为 。start1 < end2 AND start2 < end1DATEDIFF(minute, GREATEST(start1, start2), LEAST(end1, end2))

最后,由于在多天内可能存在多个具有相同流程/班次组合的结果,因此可用于将它们组合起来并应用于计算重叠的总和。GROUP BYSUM()

生成的查询将如下所示:

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()CASEGENERATE_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 运行的代码。