• 分解跨天的时间数据


    数据库环境:SQL SERVER 2005

      在百度知道看到这道题目,原问题链接 MS SQL数据库关于时间循环如何处理跨天问题

      有如下表:
      -----------------------------------------------------------------------------------------------------------------
      设备 开始时间 结束时间 总时间(分钟)
      A 2015-08-01 17:06:49 2015-08-02 03:41:32 635
      B 2015-08-01 20:54:42 2015-08-03 23:59:59 3605
      ----------------------------------------------------------------------------------------------------------------
      需求:
      1、将每个设备的时间段循环得出每天总时间
      2、1天的时间计算结果必须是1440
      3、不能用游标方式处理
      需求结果集表如下:
      -----------------------------------------------------------------------------------------------------------------
      设备 开始时间 结束时间 总时间(分钟)
      A 2015-08-01 17:06:49 2015-08-01 23:59:59 413
      A 2015-08-02 00:00:00 2015-08-02 03:41:32 222
      B 2015-08-01 20:54:42 2015-08-01 23:59:59 185
      B 2015-08-02 00:00:00 2015-08-02 23:59:59 1440
      B 2015-08-03 00:00:00 2015-08-03 23:59:59 1440
      ----------------------------------------------------------------------------------------------------------------------

      

      该问题已有网友用递归实现,如果不用递归,我们该怎么处理呢?下面,我说一下我的实现思路:

      1.求出每个设备开始时间和结束时间相差的天数

      2.生成分解后的新时间

      3.求出分解后每个设备每天的时间差(分钟),如果是一整天,则计为1440;

      如果是最后一天,则用总时间减去前面的时间总和。

      SQL实现

    /*测试数据*/
    WITH    x0
              AS ( SELECT   'A' AS sb ,
                            CONVERT(DATETIME, '2015-08-01 17:06:49') AS date_begin ,
                            CONVERT(DATETIME, '2015-08-02 03:41:32') AS date_end ,
                            635 AS total_time
                   UNION ALL
                   SELECT   'B' AS sb ,
                            CONVERT(DATETIME, '2015-08-01 20:54:42') AS date_begin ,
                            CONVERT(DATETIME, '2015-08-03 23:50:52') AS date_end ,
                            3056 AS total_time
                   UNION ALL
                   SELECT   'C' AS sb ,
                            CONVERT(DATETIME, '2015-08-04 12:40:20') AS date_begin ,
                            CONVERT(DATETIME, '2015-08-05 23:59:59') AS date_end ,
                            2119 AS total_time
                 ),/*计算两个时间点之间相差的天数*/
            x1
              AS ( SELECT   sb ,
                            date_begin ,
                            date_end ,
                            total_time ,
                            DATEDIFF(day, date_begin, date_end) AS cacl_day--开始时间和结束时间相差的天数
                   FROM     x0
                 ),/*将隔天的时间分解*/
            x2
              AS ( SELECT   sb ,
                            CASE WHEN msv.number = 0 THEN date_begin
                                 ELSE CONVERT(VARCHAR(10), DATEADD(DAY, msv.number,
                                                                  date_begin), 120)
                            END AS date_begin ,
                            CASE WHEN msv.number = x.cacl_day THEN date_end
                                 ELSE CONVERT(VARCHAR(10), DATEADD(DAY, msv.number,
                                                                  date_begin), 120)
                                      + ' 23:59:59'
                            END AS date_end ,
                            total_time ,
                            CASE WHEN msv.number = x.cacl_day THEN 1
                                 ELSE 0
                            END AS flag--如果是最后一天,标识为1,否则为0
                   FROM     x1 x ,
                            master..spt_values msv
                   WHERE    msv.type = 'P'
                            AND msv.number <= x.cacl_day
                 ),
            x3
              AS ( SELECT   sb ,
                            date_begin ,
                            date_end ,
                            total_time ,
                            CASE WHEN CONVERT(CHAR(8), date_begin, 108) = '00:00:00'
                                      AND CONVERT(CHAR(8), date_end, 108) = '23:59:59'
                                 THEN 1440
                                 ELSE DATEDIFF(MINUTE, date_begin, date_end)
                            END AS cacl_time ,--如果是一整天,那么是1440分钟,否则,2个时间相减
                            flag ,
                            ROW_NUMBER() OVER ( PARTITION BY sb ORDER BY date_end ) AS rn--行号,用于后面统计各天的剩余分钟
                   FROM     x2
                 )
        SELECT  sb ,
                date_begin ,
                date_end ,
                CASE WHEN flag = 1 THEN total_time - ( SELECT   SUM(cacl_time)
                                                       FROM     x3 x
                                                       WHERE    x.sb = x3.sb
                                                                AND x.rn < x3.rn
                                                     )
                     ELSE cacl_time--最后一天的耗时是总时间减去前面的时间总和
                END AS cacl_time
        FROM    x3 
    View Code

      我自己添加了一些测试数据,先看下原表的数据

      分解后的时间

      感兴趣的朋友,可以对比一下这2种方法实现的异同。

      

  • 相关阅读:
    协成
    进程与线程-多线程
    进程与线程2
    进程与线程
    socket编程
    常用模块二(hashlib、configparser、logging)
    异常处理
    python之路——面向对象进阶
    封装
    初识——面向对象
  • 原文地址:https://www.cnblogs.com/boss-he/p/4802324.html
Copyright © 2020-2023  润新知