Захват последовательных годовых диапазонов с перерывом в улье - PullRequest
2 голосов
/ 30 мая 2020

Я пытаюсь написать запрос в улье, чтобы вернуть данные с диапазоном лет, если они являются последовательными годами вместе с годом разрыва, если между годами есть промежутки.

Я пытаюсь обдумать это, но не могу найти logi c для достижения результатов. Как для этого работает hive logi c. Пожалуйста помоги.

Вход

group_no            year 
1111                2003
1111                2004
1111                2005
1111                2008
1111                2010
1111                2011
1111                2012
2222                2015
3333                2014
3333                2015
3333                2017
3333                2019
4444                2010
4444                2012  

Выход:

group_no year
1111    [2003-2005,2008,2010-2012]
2222    [2015]
3333    [2014-2015,2017,2019]
4444    [2010,2012]

Ответы [ 2 ]

0 голосов
/ 01 июня 2020

Новый диапазон начинается, когда (year - prev_year) > 1 or (prev_year is NULL), вы можете принять текущий год в качестве первого года для нового диапазона. Назначьте first_year всем строкам, затем вычислите last_year для каждой группы (group_no, first_year).

    with my_data as(
    select stack(14,
    1111, 2003,
    1111, 2004,
    1111, 2005,
    1111, 2008,
    1111, 2010,
    1111, 2011,
    1111, 2012,
    2222, 2015,
    3333, 2014,
    3333, 2015,
    3333, 2017,
    3333, 2019,
    4444, 2010,
    4444, 2012  
    ) as (group_no, year)
    )   

select group_no, array_sort(collect_list(case when first_year=last_year then first_year else concat(first_year,'-',last_year) end)) as year
from
(--calculate last_year
select s.group_no, s.first_year, max(year) last_year      
from
(
select group_no, year, 
       --New range starts when (year - prev_year) > 1 or (prev_year is NULL)
       --Calculate first_year for every row
       max(case when (year - prev_year) = 1 then NULL else year end) over(partition by group_no order by year rows between unbounded preceding and current row ) first_year
  from
(
select d.*,
       lag(year) over(partition by group_no order by year) prev_year
  from my_data d
)s  
)s
group by s.group_no, s.first_year
)s
group by group_no 
order by group_no

Результат:

group_no  year
1111  ["2003-2005","2008","2010-2012"]
2222  ["2015"]
3333  ["2014-2015","2017","2019"]
4444  ["2010","2012"]
0 голосов
/ 30 мая 2020

Это проблема с пробелами и островками, когда вы хотите сгруппировать вместе строки, имеющие одинаковые group_no и чьи year являются последовательными.

Вот подход с использованием оконных функций: идея заключается в использовать разницу между row_number() и year для построения групп. Затем вы можете агрегировать один раз для каждой группы смежных записей и, наконец, агрегировать по group_no.

select 
    group_no, 
    collect_list(
        case when min_year <> max_year 
            then concat(min_year, '-', max_year)
            else min_year
        end
    ) year
from (
    select group_no, min(year) min_year, max(year) max_year
    from (
        select  t.*, row_number() over(partition by group_no order by year) rn
        from mytable t
    ) t
    group by group_no, year - rn
) t
group by group_no

Я не уверен, поддерживает ли улей order by в collect_list() в качестве агрегатной функции - похоже, это работает, когда используется как оконная функция, поэтому это может быть лучше:

select distinct 
    group_no, 
    collect_list(
        case when min_year <> max_year 
            then concat(min_year, '-', max_year)
            else min_year
        end
    ) over(
        partition by group_no 
        order by min_year
        rows between unbounded preceding and unbounded following
    ) year
from (
    select group_no, min(year) min_year, max(year) max_year
    from (
        select  t.*, row_number() over(partition by group_no order by year) rn
        from mytable t
    ) t
    group by group_no, year - rn
) t
...