SQL Query to Collapse Duplicate Values By Date Range

前端 未结 4 2094
后悔当初
后悔当初 2020-12-12 23:19

I have a table with the following structure: ID, Month, Year, Value with values for one entry per id per month, most months have the same value.

I would like to crea

4条回答
  •  醉酒成梦
    2020-12-12 23:33

    I couldn't get the response from ngz to work when the input table contains multiple ids and date ranges that span years. I have a solution that does work, but with qualifications. It will only give you the correct answers if you know that you have a row for every month/year/id combination within the range. If there are "holes" it won't work. If you have holes, I know of know good way to do it other than writing some PL/SQL and using a cursor loop to create a new table in the format you want.

    By the way, this is why data modeled this way is an abomination. You should always store stuff as start/from range records, not as discrete time period records. It's trivial to transform the former into the latter with a "multiplier" table, but it's almost impossible (as you've seen) to go the other direction.

    SELECT ID
         , VALUE
         , start_date
         , end_date
      FROM (SELECT ID
                 , VALUE
                 , start_date
                 , CASE
                      WHEN is_last = 0
                         THEN LEAD(end_date) OVER(PARTITION BY ID ORDER BY start_date)
                      ELSE end_date
                   END end_date
                 , is_first
              FROM (SELECT ID
                         , VALUE
                         , TO_CHAR(the_date, 'YYYY.MM') start_date
                         , TO_CHAR(NVL(LEAD(the_date - 31) OVER(PARTITION BY ID ORDER BY YEAR
                                      , MONTH), the_date), 'YYYY.MM') end_date
                         , is_first
                         , is_last
                      FROM (SELECT ID
                                 , YEAR
                                 , MONTH
                                 , TO_DATE(TO_CHAR(YEAR) || '.' || TO_CHAR(MONTH) || '.' || '15', 'YYYY.MM.DD') the_date
                                 , VALUE
                                 , ABS(SIGN(VALUE -(NVL(LAG(VALUE) OVER(PARTITION BY ID ORDER BY YEAR
                                                       , MONTH), VALUE - 1)))) is_first
                                 , ABS(SIGN(VALUE -(NVL(LEAD(VALUE) OVER(PARTITION BY ID ORDER BY YEAR
                                                       , MONTH), VALUE - 1)))) is_last
                              FROM test_table)
                     WHERE is_first = 1
                        OR is_last = 1))
     WHERE is_first = 1
    

提交回复
热议问题