Сокращающиеся интервалы окна

0

У меня есть база данных, такая как:

select * from (
  values ('A', 1, 2), ('A', 2, 3), ('A', 3, 4),
         ('B', 4, 5), ('B', 5, 6), ('A', 6, 7),
         ('C', 7, 8), ('C', 8, 9)
) example_table("state", "start", "end")

-- example table: 
-- state start stop
--     A    t1   t2
--     A    t2   t3
--     A    t3   t4
--     B    t4   t5
--     B    t5   t6
--     A    t6   t7
--     C    t7   t8
--     C    t8   t9

Я хочу свернуть интервалы по state а также соблюдать промежуточные переключатели состояния:

state start stop
    A    t1   t4
    B    t4   t6
    A    t6   t7
    C    t7   t9

Просто использование group by state не будет работать, так как в выводе для данного state имеется несколько строк.

Это похоже на использование оконных функций, но я не уверен, что разбить строки.

Я хотел бы создать group_id как следующий шаг как промежуточный шаг:

group state start stop
    1     A    t1   t2
    1     A    t2   t3
    1     A    t3   t4
    2     B    t4   t5
    2     B    t5   t6
    3     A    t6   t7
    4     C    t7   t8
    4     C    t8   t9

Затем я мог бы группироваться по group и выбирать min(start) и max(stop), но я не знаю, как создать эту переменную (эффективно). В RI будет использовать функцию rle чтобы сделать это, но я не знаю эквивалента Presto.

Теги:
prestodb

1 ответ

0
Лучший ответ

Этот ответ был обновлен, чтобы отразить следующий успешный ответ

with example_table("state", "start", "end") as (
  values ('A', 1, 2), ('A', 2, 3), ('A', 3, 4),
         ('B', 4, 5), ('B', 5, 6), ('A', 6, 7),
         ('C', 7, 8), ('C', 8, 9)
), table_with_lags as (
  -- detect state changes by observing the lagged value
  select *, lag(state) over(order by start) as lag_state,
  -- need to track the final value since it may be lost below
  last_value("end") over(order by start rows between 
                         0 preceding and unbounded following)
  as end_period
  from example_table
)
select state, start, 
       -- force-re-establish the start(+1) = end(0) link;
       --   at the end of the period, override this with the
       --   final observed value instead of null
       lead(start, 1, end_period) over(order by start) as "end"
from table_with_lags
-- lag_state will be null for the first row
where state <> lag_state or lag_state is null
order by start

С выходом:

state start stop
    A     1    4
    B     4    6
    A     6    7
    C     7    9

rows between 0 preceding and unbounded following битом немного подробные, поэтому вы также можете перевернуть логику и выполнить:

table_with_leads as (
  select state, start, "end", 
         lead(state) over(order by start) as lead_state,
         first_value(start) over(order by start) as start_period
  from example_table
)
select state, lag("end", 1, start_period) over(order by start) as start, "end"
from table_with_lags
where state <> lead_state or lead_state is null
order by start

оригинальный ответ

Следующие работы, но не работают в масштабе (даже на 10% подвыборке данных, я получаю ошибку "превышение локальной памяти"):

with switches as (
  -- coalesce since the first row will be NULL, need it false
  select *, coalesce(state <> lag(state) over(order by start), false) switched
  from (
    values ('A', 1, 2), ('A', 2, 3), ('A', 3, 4),
           ('B', 4, 5), ('B', 5, 6), ('A', 6, 7),
           ('C', 7, 8), ('C', 8, 9)
  ) example_table("state", "start", "stop")
), groups as (
  -- create the group ID as the accumulation of the state switches
  --   since only one state switch can happen per group
  select *, sum(cast(switched as bigint)) over (order by start) group_id
  from switches
)
select min(state) state, min(start) start, max(stop) stop
from groups group by group_id order by start;

-- state start stop
--     A     1    4
--     B     4    6
--     A     6    7
--     C     7    9

В настоящее время я нашел успех, временно сохраняя groups в виде таблицы, а затем отдельно select из groups, что, как представляется, оборачивается проблемой ОЗУ (что несколько удивительно для меня). Это вряд ли кажется идеальным, но по мере того, как он выполняет свою работу, я доволен придерживаться этого на данный момент.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню