【问题标题】:Creating n minute intervals per table row为每个表行创建 n 分钟间隔
【发布时间】:2021-11-30 00:34:53
【问题描述】:

我正在尝试根据表格获取时间间隔。

我的源表是这样的:

ID OTHER_DATA TIME_BEG TIME_END DURATION
1 abcd 10:00 11:00 15
2 xyzt 16:00 17:00 30

期望的输出:

ID OTHER_DATA ITVL_BEG ITVL_END
1 abcd 10:00 10:15
1 abcd 10:15 10:30
1 abcd 10:30 10:45
1 abcd 10:45 11:00
2 xyzt 16:00 16:30
2 xyzt 16:30 17:00

TIME_BEGTIME_ENDVARCHAR 列,但我也将它们设置为 DAY TO SECOND INTERVAL,此处未显示(分别为 TIME_BEG_INT 和 TIME_END_INT)。

基本上我需要在一个 SQL 中复制每一行 TRUNC (EXTRACT (DAY FROM 24 * 60 * (TIME_END_INT - TIME_BEG_INT)) / DURATION) 次并将 this*DURATION 添加到我的日期中。

感谢任何帮助。

【问题讨论】:

    标签: sql oracle datetime-conversion


    【解决方案1】:

    如果您使用间隔:

    CREATE TABLE table_name (ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS
    SELECT 1, 'abcd', INTERVAL '10:00' HOUR TO MINUTE, INTERVAL '11:00' HOUR TO MINUTE, INTERVAL '15' MINUTE FROM DUAL UNION ALL
    SELECT 2, 'xyzt', INTERVAL '16:00' HOUR TO MINUTE, INTERVAL '17:00' HOUR TO MINUTE, INTERVAL '30' MINUTE FROM DUAL;
    

    那么你可以使用:

    WITH range (ID, OTHER_DATA, TIME_BEG, TIME_INT_END, TIME_END, DURATION) AS (
      SELECT ID,
             OTHER_DATA,
             TIME_BEG,
             LEAST(time_beg + duration, time_end),
             TIME_END,
             DURATION
      FROM   table_name
    UNION ALL
      SELECT ID,
             OTHER_DATA,
             TIME_INT_END,
             LEAST(time_int_end + duration, time_end),
             TIME_END,
             DURATION
      FROM   range
      WHERE  time_int_end < time_end
    )
    SEARCH DEPTH FIRST BY id SET id_order
    SELECT ID,
           OTHER_DATA,
           TIME_BEG AS itvl_beg,
           TIME_INT_END AS itvl_end
    FROM   range;
    

    哪些输出:

    ID OTHER_DATA ITVL_BEG ITVL_END
    1 abcd +000000000 10:00:00.000000000 +000000000 10:15:00.000000000
    1 abcd +000000000 10:15:00.000000000 +000000000 10:30:00.000000000
    1 abcd +000000000 10:30:00.000000000 +000000000 10:45:00.000000000
    1 abcd +000000000 10:45:00.000000000 +000000000 11:00:00.000000000
    2 xyzt +000000000 16:00:00.000000000 +000000000 16:30:00.000000000
    2 xyzt +000000000 16:30:00.000000000 +000000000 17:00:00.000000000

    如果您将值作为字符串,那么您可以先将它们转换为间隔:

    CREATE TABLE table_name (ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS
    SELECT 1, 'abcd', '10:00', '11:00', 15 FROM DUAL UNION ALL
    SELECT 2, 'xyzt', '16:00', '17:00', 30 FROM DUAL;
    
    WITH data(ID, OTHER_DATA, TIME_BEG, TIME_END, DURATION) AS (
      SELECT ID,
             OTHER_DATA,
             TO_DSINTERVAL('0 '||TIME_BEG||':00'),
             TO_DSINTERVAL('0 '||TIME_END||':00'),
             NUMTODSINTERVAL(DURATION, 'MINUTE')
      FROM   table_name
    ),
    range (ID, OTHER_DATA, TIME_BEG, TIME_INT_END, TIME_END, DURATION) AS (
      SELECT ID,
             OTHER_DATA,
             TIME_BEG,
             LEAST(time_beg + duration, time_end),
             TIME_END,
             DURATION
      FROM   data
    UNION ALL
      SELECT ID,
             OTHER_DATA,
             TIME_INT_END,
             LEAST(time_int_end + duration, time_end),
             TIME_END,
             DURATION
      FROM   range
      WHERE  time_int_end < time_end
    )
    SEARCH DEPTH FIRST BY id SET id_order
    SELECT ID,
           OTHER_DATA,
           TIME_BEG AS itvl_beg,
           TIME_INT_END AS itvl_end
    FROM   range;
    

    db小提琴here

    【讨论】:

      【解决方案2】:

      这是基于pre-intervalDATE计算的经典解决方案

      with time_int(ID, OTHER_DATA, ITVL_BEG, ITVL_END, DURATION, TIME_END) as (
      select 
       ID, OTHER_DATA, TIME_BEG, 
       to_char(to_date(time_beg,'HH24:mi')+duration/(24*60),'HH24:mi'), 
       DURATION, TIME_END 
      from tab
      union all
      select 
       ID, OTHER_DATA, ITVL_END, 
       to_char(to_date(ITVL_END,'HH24:mi')+duration/(24*60),'HH24:mi'), 
       DURATION, TIME_END 
      from time_int
      where ITVL_END <= TIME_END
      )
      select 
         ID, OTHER_DATA, ITVL_BEG, ITVL_END
      from time_int
      order by 1,3;
      
              ID OTHE ITVL_ ITVL_
      ---------- ---- ----- -----
               1 abcd 10:00 10:15
               1 abcd 10:15 10:30
               1 abcd 10:30 10:45
               1 abcd 10:45 11:00
               1 abcd 11:00 11:15
               2 xyzt 16:00 16:30
               2 xyzt 16:30 17:00
               2 xyzt 17:00 17:30
      

      递归 CTEstep 一起使用,基于以下计算得到下一个区间边界(假设您的时间存储为 VARCHAR2)

      to_char(to_date(time_beg,'HH24:mi')+duration/(24*60),'HH24:mi')
      

      请注意,您可以将10:00 转换为日期,Oracle 会提供您不需要的默认缺失日、月和年,因为在增加duration 之后,您会转换回@ 987654326@字符串。

      【讨论】:

        猜你喜欢
        • 2016-08-18
        • 1970-01-01
        • 2013-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-26
        • 1970-01-01
        • 2015-01-03
        相关资源
        最近更新 更多