选择/查询计算没有周末的时间戳之间的时间

时间:2016-12-13 20:58:45

标签: mysql

提出的问题是计算每行返回的时间(“响应时间”)在2个时间戳(“StartDateTime”和“EndDateTime”)之间,不包括周末。不考虑工作时间或假期。

本案例中的周末定义为周六00:00:00至周日23:59:59。

为这个问题提出解决方案时遇到了困难,所以我想分享我的最终产品。在网上找到了很多解决方案,但大多数都使用了我无法在此应用程序中使用的日历表,或者有一个我不理解的逻辑。解决方案分享如下请随时根据问题提供自己的解决方案,或更正我在代码中看到的任何错误。的问候,

编辑:根据@JuanCarlosOropeza解决方案提供的评论,我提出的并不是最优的。为他提供样本数据以转发不同的解决方案。如果有人有改进,也可以随意参加。

CREATE TABLE SourceTable
    (`id` int, `StartDateTime` datetime, `EndDateTime` datetime)
;

INSERT INTO SourceTable
    (`id`, `StartDateTime`, `EndDateTime`)
VALUES
    (1, '2016-09-20 12:52:00', '2016-09-23 13:15:00'),
    (2, '2016-09-19 19:15:00', '2016-09-22 19:15:00'),
    (3, '2016-09-01 10:35:00', '2016-09-06 13:15:00'),
    (4, '2016-09-26 10:34:00', '2016-09-29 11:25:00'),
    (5, '2016-09-01 13:01:00', '2016-09-06 14:55:00'),
    (6, '2016-09-05 02:21:00', '2016-09-08 19:15:00'),
    (7, '2016-09-27 14:14:00', '2016-10-01 19:15:00'),
    (8, '2016-09-27 04:18:00', '2016-09-30 14:15:00'),
    (9, '2016-09-01 14:50:00', '2016-09-06 17:25:00'),
    (10, '2016-09-20 12:52:00', '2016-09-23 13:15:00'),
    (11, '2016-09-26 02:14:00', '2016-09-29 10:15:00'),
    (12, '2016-09-01 12:04:00', '2016-09-06 17:05:00'),
    (13, '2016-09-20 15:30:00', '2016-09-23 15:15:00'),
    (14, '2016-09-02 16:04:00', '2016-09-07 20:55:00'),
    (15, '2016-09-23 10:41:00', '2016-09-28 13:05:00'),
    (16, '2016-09-27 16:28:00', '2016-10-01 13:15:00'),
    (17, '2016-09-27 15:33:00', '2016-10-01 22:45:00'),
    (18, '2016-09-20 12:53:00', '2016-09-23 13:25:00'),
    (19, '2016-09-19 13:49:00', '2016-09-22 13:05:00'),
    (20, '2016-09-20 13:46:00', '2016-09-23 13:15:00'),
    (21, '2016-09-01 16:32:00', '2016-09-06 18:05:00'),
    (22, '2016-09-01 10:35:00', '2016-09-06 22:45:00'),
    (23, '2016-09-26 12:40:00', '2016-09-29 12:35:00'),
    (24, '2016-09-27 10:37:00', '2016-09-30 21:25:00'),
    (25, '2016-09-27 09:41:00', '2016-09-30 15:15:00'),
    (26, '2016-09-16 02:09:00', '2016-09-21 10:05:00'),
    (27, '2016-09-20 15:13:00', '2016-09-23 15:15:00'),
    (28, '2016-09-20 15:30:00', '2016-09-23 15:15:00'),
    (29, '2016-09-27 09:55:00', '2016-09-30 13:25:00'),
    (30, '2016-09-27 04:18:00', '2016-09-30 14:15:00')
;

1 个答案:

答案 0 :(得分:0)

我考虑到以下逻辑假设创建了这个解决方案。

StartDateTime总是在EndDateTime之前发生(虽然有一些没有,但它正确地计算了时差)

周StartDateTime发生:WEEK(StartDateTime,1)

周EndDateTime发生:WEEK(EndDateTime,1)

周末开始StartDateTime:ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime))

第一个周末后的工作周开始:ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),7-WEEKDAY(StartDateTime))

完整查询:

SELECT
    id,
    StartDateTime,
    EndDateTime,
    CASE
    WHEN ( WEEK(EndDateTime,1) = WEEK(StartDateTime,1) )
        THEN
            CASE
            WHEN ( StartDateTime >= ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime)) )
                THEN SEC_TO_TIME(0)
                ELSE
                    CASE
                    WHEN ( EndDateTime >= ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime)) )
                        THEN ( TIMEDIFF(ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime)),StartDateTime) )
                        ELSE ( TIMEDIFF(EndDateTime,StartDateTime) )
                    END
            END
        ELSE
            CASE
            WHEN ( StartDateTime >= ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime)) )
                THEN
                    CASE
                    WHEN ( EndDateTime >= ADDDATE(ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime)),(WEEK(EndDateTime,1) - WEEK(StartDateTime,1)) * 7) )
                        THEN ( SEC_TO_TIME(120*3600*(WEEK(EndDateTime,1) - WEEK(StartDateTime,1))) )
                        ELSE ( SEC_TO_TIME(120*3600*(WEEK(EndDateTime,1) - WEEK(StartDateTime,1) - 1) + TIME_TO_SEC(TIMEDIFF(EndDateTime, ADDDATE(ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),7-WEEKDAY(StartDateTime)),7*(WEEK(EndDateTime,1) - WEEK(StartDateTime,1) - 1))))) )
                    END
                ELSE
                    CASE
                    WHEN ( EndDateTime >= ADDDATE(ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime)),(WEEK(EndDateTime,1) - WEEK(StartDateTime,1)) * 7) )
                        THEN ( SEC_TO_TIME(120*(WEEK(EndDateTime,1) - WEEK(StartDateTime,1)) + TIME_TO_SEC(TIMEDIFF(ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime)),StartDateTime))) )
                        ELSE ( SEC_TO_TIME(TIME_TO_SEC(TIMEDIFF(EndDateTime, ADDDATE(ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),7-WEEKDAY(StartDateTime)),7*(WEEK(EndDateTime,1) - WEEK(StartDateTime,1) - 1)))) + TIME_TO_SEC(TIMEDIFF(ADDDATE(TIMESTAMP(DATE(StartDateTime),'00:00:00'),5-WEEKDAY(StartDateTime)),StartDateTime))) )
                    END
            END
    END as ResponseTime
FROM
    SourceTable;

第一个CASE检查两个时间戳是否在同一周发生。第二层检查StartDateTime是否在第一个周末发生。第三层检查EndDateTime是否在周末发生。根据这些考虑因素输出正确的计算结果。