Aggregate periods using recursive queries

后端 未结 1 1551
广开言路
广开言路 2021-01-27 18:29

I need to merge overlapping periods (defined by FROM and TO variables) of sequential events (with identifier NUM) for each group (ID) with a \"lookahead buffer\", meaning that i

1条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-01-27 19:06

    You should use the RESET WHEN window modifier in your analytic functions (LAG in Teradata 16, or MAX in earlier ones); don't use a recursive query.

    Update:

    DROP TABLE MY_TABLE;
    CREATE VOLATILE TABLE MY_TABLE 
    ( id          INTEGER
    , num         INTEGER
    , from_value  INTEGER
    , to_value    INTEGER
    , lookahead   INTEGER
    ) ON COMMIT PRESERVE ROWS;
    
    INSERT INTO MY_TABLE VALUES (1, 1, 1,  10, 5);
    INSERT INTO MY_TABLE VALUES (1, 2, 13, 20, 5);
    INSERT INTO MY_TABLE VALUES (1, 3, 21, 25, 3);
    INSERT INTO MY_TABLE VALUES (1, 4, 29, 31, 3);
    INSERT INTO MY_TABLE VALUES (1, 5, 40, 50, 3);
    
    INSERT INTO MY_TABLE VALUES (2, 1, 1, 10, 5);
    INSERT INTO MY_TABLE VALUES (2, 2, 20, 30, 15);
    INSERT INTO MY_TABLE VALUES (2, 3, 40, 41, 5);
    INSERT INTO MY_TABLE VALUES (2, 4, 100, 200, 5);
    INSERT INTO MY_TABLE VALUES (2, 5, 300, 400, 3);
    
    
    SELECT  id, first_from_value, to_value
    FROM  ( SELECT  id
                  , to_value
                  , CASE WHEN overlaps_flag = 1
                      THEN  NULL
                      ELSE  COALESCE 
                            ( MIN (from_value) 
                                OVER (PARTITION BY id
                                      ORDER BY from_value
                                      RESET WHEN MAX (overlaps_flag) 
                                                   OVER (PARTITION BY id 
                                                         ROWS BETWEEN 
                                                              1 PRECEDING 
                                                          AND 1 PRECEDING) = 0
                                      ROWS BETWEEN UNBOUNDED PRECEDING 
                                               AND 1 PRECEDING)
                            , from_value )
                    END AS first_from_value
            FROM  ( SELECT  id, from_value, to_value
                          , MAX (from_value) 
                              OVER (PARTITION BY id 
                                    ORDER BY from_value 
                                    ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING)
                              AS next_from_value
                          , CASE WHEN to_value + lookahead + 1 >= next_from_value
                              THEN 1 ELSE 0 
                            END AS overlaps_flag
                    FROM  my_table
                  ) AS a
          ) AS a
    WHERE first_from_value IS NOT NULL
    ORDER BY 1, 2
    
    id  first_from_value    to_value
    1   1                   31
    1   40                  50
    2   1                   10
    2   20                  41
    2   100                 200
    2   300                 400
    

    0 讨论(0)
提交回复
热议问题