Home > other >  How to create timeline by adding same intervals x number of times? - SQL
How to create timeline by adding same intervals x number of times? - SQL

Time:08-15

I want to create a table with timeline data by repeatedly adding the same intervals for each id a certain # of times denoted by iterations (constant per id). My current table has the base repetition of this timeline.

Sample Input (iteration 1):

id    start_time         end_time           iterations
1     00:00:00.00000     00:00:00.05300     3
1     00:00:00.05300     00:00:00.07600     3

Desired Output:

id    start_time         end_time       
1     00:00:00.00000     00:00:00.05300
1     00:00:00.05300     00:00:00.07600
1     00:00:00.07600     00:00:00.12900
1     00:00:00.12900     00:00:00.15200 
1     00:00:00.15200     00:00:00.20500
1     00:00:00.20500     00:00:00.22800 

Logic:

  • iteration 2: first end_time = 0.076 (0.053 - 0.000) = 0.129
  • iteration 2: second end_time = 0.129 (0.076 - 0.053) = 0.152
  • iteration 3: first end_time = 0.152 (0.053 - 0.000) = 0.205
  • iteration 3: second end_time = 0.205 (0.076 - 0.053) = 0.228

What I've Tried:

WITH cte AS (
SELECT
  *
  , SUM(TIME_DIFF(end_time, start_time, MILLISECOND)) 
      OVER (PARTITION BY id ORDER BY start_time 
      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
        AS running_end_time
FROM my_table 
  , UNNEST(GENERATE_ARRAY(1, iterations))
)

SELECT
  id
  , CASE 
       WHEN MIN(aggregated_start_time) OVER (PARTITION BY id) = FIRST_VALUE 
         OVER (PARTITION BY id) THEN TIME(0, 0, 0)
       ELSE LAG(TIME(0, 0, 0), INTERVAL running_end_time MILLISECOND) 
         OVER (PARTITION BY id) END AS start_time
  , TIME_ADD(TIME(0, 0, 0), INTERVAL running_end_time MILLISECOND)
        AS end_time 
FROM cte

However, this doesn't work because although my cte creates the necessary number of records, it doesn't order them the right way which leads to adding the wrong intervals. Any help would really be appreciated!

CodePudding user response:

Consider below approach

select id, 
  time_add(start_time, interval repeat*step millisecond) as start_time,
  time_add(end_time, interval repeat*step millisecond) as end_time,
from (
  select *, 
    sum(time_diff(end_time, start_time, millisecond)) over(partition by id) step,
    max(end_time) over(partition by id) max_end_time
  from your_table
), unnest(generate_array(0, iterations - 1)) repeat                

if applied to sample data in your question - output is

enter image description here

CodePudding user response:

Below query is based on my incomplete understading of your requiements focusing on implementing below logic:

  • first end_time = MAX(end_time) OVER (PARTITION BY id) (0.053 - 0.000) = 0.076 0.053 = 0.129
  • second end_time = MAX(end_time) OVER (PARTITION BY id) (0.053 - 0.000) (0.076 - 0.053)` = 0.129 0.023 = 0.152
WITH my_table AS (
  select 1 id, TIME '00:00:00.00000' start_time, TIME '00:00:00.05300' end_time, 2 iterations union all
  select 1, '00:00:00.05300', '00:00:00.07600', 2
),
my_table0 AS (
  SELECT *,
         TIME_DIFF(end_time, start_time, MILLISECOND) AS diff,
         MAX(end_time) OVER (PARTITION BY id) AS max_end_time,
    FROM my_table
)
SELECT id, start_time, end_time FROM my_table0
 UNION ALL
SELECT id,
       TIME_ADD(max_end_time, INTERVAL SUM(diff) OVER w - diff MILLISECOND) AS start_time,
       TIME_ADD(max_end_time, INTERVAL SUM(diff) OVER w MILLISECOND) AS end_time,
  FROM my_table0
WINDOW w AS (PARTITION BY id ORDER BY start_time)
 ORDER BY start_time
;

Query results:
 ----- ---- ----------------- ----------------- 
| Row | id |   start_time    |    end_time     |
 ----- ---- ----------------- ----------------- 
|   1 |  1 | 00:00:00        | 00:00:00.053000 |
|   2 |  1 | 00:00:00.053000 | 00:00:00.076000 |
|   3 |  1 | 00:00:00.076000 | 00:00:00.129000 |
|   4 |  1 | 00:00:00.129000 | 00:00:00.152000 |
 ----- ---- ----------------- ----------------- 
  • Related