Eu tenho uma tabela como você pode ver abaixo:
create table z_test_duration
( Days date,
Status char(8)
);
Os dados da amostra são como abaixo:
Dias | Status |
---|---|
01/01/2022 | sobre |
02/01/2022 | sobre |
03/01/2022 | sobre |
04/01/2022 | desligado |
05/01/2022 | sobre |
06/01/2022 | desligado |
07/01/2022 | sobre |
08/01/2022 | sobre |
09/01/2022 | desligado |
O resultado desejado é este
NA DATA | OFF_DATE | COUNT_OF_ACTIVE_DAYS |
---|---|---|
01/01/2022 | 04/01/2022 | 3 |
05/01/2022 | 06/01/2022 | 1 |
07/01/2022 | 09/01/2022 | 2 |
Minha solução até agora é esta:
select min(days) on_date,
off_day off_date,
off_day - min(days) cnt
from (select t1.off_day,
t1.prev_offday,
t2.days
from (
select t.days off_day,
nvl(lag(t.days, 1) over(order by t.days),convert(datetime, '1/1/2022') - 100) prev_offday
from z_test_duration t
where t.status = 'off'
) t1
inner join z_test_duration t2
on t2.days > t1.prev_offday
and t2.days < t1.off_day)
group by off_day;
Estou pensando se existem maneiras melhores de resolver isso, seria apreciado se você compartilhasse sua maneira de resolver isso.
Desde já, obrigado.
Este é um problema de 'ilhas'.
Uma solução popular e eficiente é numerar as linhas na ordem desejada. Quando há uma lacuna na sequência, a diferença entre a coluna de ordenação e o número da linha também salta.
Vamos ver isso passo a passo. Primeiro, a numeração:
Observe que os
Seq
valores aumentam na mesma taxarn
até que haja uma lacuna. Podemos ver isso mais claramente subtraindorn
doSeq
valor.A única pequena complicação aqui é
Seq
umdate
, então precisamos convertê-lo em um número antes de subtrair. Eu usei aDATEDIFF
função aqui, mas qualquer método consistente de transformar uma data em um número serviria.Os
diff
valores são os mesmos para cada elemento contíguo em um grupo.Agora que sabemos como agrupar, a consulta final segue diretamente:
db<> demonstração online de violino