将持续时间记录转换为时间表

5us2dqdw  于 2021-07-24  发布在  Java
关注(0)|答案(2)|浏览(318)

我在powerquery中创建了一个相当复杂的转换,由于性能原因,我需要将它推回到sqlserver后端。然而,我在实现它的时候遇到了麻烦-也许你可以帮我一些关于如何解决这个问题的线索。
我有一个源表,其中包含具有持续时间的事务-即开始和结束时间戳,这些事务可以分布在多天内。我想将该表转换为一天中的时间尺度,以分析这些交易如何在0:00:00到23.59:59之间的一天中传播。
使用时间百分比,分布是线性的。
如果我有这样一个源表示例:

Record_ID   StartTime           StopTime           Measure
----------------------------------------------------------
   1        2020.06.06  9:45    2020.06.06 18:31      682
   2        2020.06.06  23:21   2020.06.07 10:51      543
   3        2020.06.06  16:38   2020.06.08 9:49     20921

结果如下:

Record_ID   StartTime           StopTime              Measure
--------------------------------------------------------------
   1        2020.06.06  9:45    2020.06.06  18:31       682
   2        2020.06.06  23:21   2020.06.06  23:59        30,5
   2        2020.06.07  0:00    2020.06.07  10:51       512,5
   3        2020.06.06  16:38   2020.06.06  23:59      3739,3
   3        2020.06.07  0:00    2020.06.07  23:59     12189,2
   3        2020.06.08  0:00    2020.06.08  9:49       4992,5

计算注意事项:
对于记录1-不需要转换,因为这不是重叠的
对于记录2-它与一个午夜重叠,因此创建了两个记录,以分钟为单位称重
5.61% * 543 = 30.5
94.39% * 543 = 512.5
对于记录3-它与多个午夜重叠,因此根据分钟数再次创建多个记录。如果涵盖多天,那么我将需要更多的0:00-23:59类型的记录,以涵盖整个期间
17.87% * 20921 = 3739.3
58,26% * 20921 = 12189.2
23.86% * 20921 = 4992.5
有没有我可以使用的模式参考?在sql中可以这样做吗?有没有可能不用循环呢?

hwamh0ep

hwamh0ep1#

可以使用递归cte:

with cte as (
      select Record_ID, StartTime, endTime, Measure
      from t
      union all
      select record_id, convert(datetime, dateadd(day, 1, convert(date, StartTime))),
             endtime, measure
      from cte
      where datediff(day, starttime, endtime) > 0
     )
select cte.*,
       measure * (diff * 1.0 / sum(diff) over (partition by record_id)) as measure
from (select record_id, starttime,
             (case when datediff(day, starttime, endtime) = 0
                   then endtime
                   else dateadd(day, 1, convert(date, StartTime))
              end) as endtime,
             measure
      from cte
     ) cte cross apply
     (values (datediff(second, starttime, endtime))) v(diff);

请注意,这将stoptime注册为第二天的开始,因此没有间隔。这使得措施的分配更加准确。
这是一把小提琴。

mmvthczy

mmvthczy2#

另一个选项是创建日期维度/日历表。然后你可以这样做:

WITH cte_dates
as
(
    SELECT m.*,
        CASE WHEN m.StartTime < ad.TheDate THEN ad.theDate ELSE m.StartTime END as newStartTime , 
        CASE WHEN ad.theNextDay < m.StopTime THEN ad.theNextDay ELSE m.StopTime END as newStopTime

    FROM myTable m
    JOIN allDates ad
        ON ad.theDate between  cast(m.StartTime as date) and cast(m.StopTime as date)
)
SELECT cd.Record_ID,1.0 * datediff(MINUTE,cd.newStartTime , cd.newStopTime) / datediff(MINUTE,cd.StartTime,cd.StopTime)  * measure as measure
FROM cte_dates cd

相关问题