Как объединить записи с одинаковыми столбцами и расширить диапазон времени? - PullRequest
1 голос
/ 01 марта 2020

Как объединить записи с одинаковыми столбцами и расширить временной диапазон?

Примеры таблиц:


  id | date_from | date_to | param1 | param2  |     |   
 ----|-----------|---------|--------|---------|-----|--- 
   1 |      2009 |    2010 | 'A'    |         | 'A' |   
   1 |      2009 |    2010 | 'A'    | 'A'     |     |   
   1 |      2011 |    2012 | 'A'    | 'A'     |     |   
   1 |      2013 |    2014 | 'B'    | 'B'     |     |   
   1 |      2015 |    2016 | 'A'    | 'A'     |     |   
   1 |      2017 |    2018 | 'A'    | 'A'     |     |   

Это должно быть так:


  id | date_from | date_to | param1 | param2  
 ----|-----------|---------|--------|--------- 
   1 |      2009 |    2012 | 'A'    | 'A'     
   1 |      2013 |    2014 | 'B'    | 'B'     
   1 |      2015 |    2018 | 'A'    | 'A'     

Я пытался использовать оконные функции, но я не знаю, что делать дальше

SELECT ROW_NUMBER() OVER(partition BY id ORDER BY date_from ASC) AS step, 
       dense_rank() OVER(partition BY id ORDER BY param1, param2) AS rnk, 
       * 
FROM Table

Ответы [ 3 ]

1 голос
/ 01 марта 2020

1) решение плотной_ранки:

with tbl_with_group as (
    select 
        t.*,
        dense_rank() over(partition BY id order BY date_from) - dense_rank() OVER(partition BY id, param1, param2 order by date_from) group_number
    from 
        table t
)
select 
    id, min(date_from), max(date_to), param1, param2
from 
    tbl_with_group 
group by 
    id, group_number, param1, param2

2) решение с задержкой:

with tbl_with_delimiter as (
    select 
        t.*,
        case when 
            lag(param1) over(partition by id order by date_from) = param1 and
            lag(param2) over(partition by id order by date_from) = param2
        then 0 else 1 end is_new_group_start
    from 
        table t
),
tbl_with_group as (
    select 
        t.*,
        sum(is_new_group_start) over(partition by id order by date_from) group_number
    from 
        tbl_with_delimiter t
)
select 
    id, min(date_from), max(date_to), param1, param2
from 
    tbl_with_group 
group by 
    id, group_number, param1, param2
order by
    id, group_number
1 голос
/ 01 марта 2020

Вы можете использовать lag() и найти группировку и выполнить агрегацию:

select id, min(date_from) as date_from, max(date_to) as date_to, param1, param2 
from (select t.*,
             sum(case when (date_from - prev_to) = 1 then 0 else 1 end) over (partition by id, param1, param2 order by date_from) as grp
      from (select t.*, 
                   lag(date_to) over (partition by id, param1, param2 order by date_from) as prev_to
            from table t
           ) t
     ) t
group by id,  param1, param2, grp
order by id, date_from;
0 голосов
/ 01 марта 2020

В отсутствие каких-либо других объяснений я должен предположить, что даты «от» и «до» могут произвольно перекрываться или иметь пробелы. Чтобы решить эту проблему, я рекомендую расширить данные для каждого отдельного года, а затем рассматривать это как простую проблему пробелов и островков:

select id, min(date_from), max(date_to), param1, param2
from (select t.*,
             dense_rank() over (partition by param1, param2 order by gs.y) as seqnum
      from t cross join lateral
           generate_series(t.date_from, t.date_to, 1) as gs(y)
     ) t
group by id, (y - seqnum), param1, param2;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...