Возвращать строки, которые имеют 3 или более последовательных значения по шаблону - PullRequest
0 голосов
/ 09 января 2019

Я пробовал метод Табибитозан, но не помог. Можете ли вы предложить другое решение для сценария ниже.

Использование Oracle 11g:

Пожалуйста, найдите формат таблицы ниже,

Region  Date      Value
East    1/1/2018    1
East    1/2/2018    1
East    1/3/2018    0
East    1/4/2018    1
East    1/6/2018    1
East    1/7/2018    0
West    1/9/2018    0
West    1/10/2018   0
West    2/3/2018    1
West    2/4/2018    1
West    2/5/2018    1
West    2/8/2018    0
West    2/9/2018    0
West    2/10/2018   0
West    2/11/2018   1
West    2/12/2018   0
West    2/13/2018   1
West    2/14/2018   1
West    2/17/2018   0
West    2/18/2018   0
West    2/19/2018   1
West    2/20/2018   0
West    2/21/2018   1
West    2/22/2018   0
West    2/23/2018   1

Мой вывод должен содержать строки, которые имеют три или более последовательных 1-х и со строками, которые имеют только один 0 между 1-м.

Примечание: Группировка по регионам и Заказ по дате. Дата в столбце Дата не может содержать все дни. Скажем, в приведенном выше 1/6/2018 отсутствует, что нормально. Мне нужно искать столбец «Значение», который следует шаблону, упорядоченный по дате и сгруппированный по регионам.

East    1/1/2018    1
East    1/2/2018    1
East    1/3/2018    0
East    1/4/2018    1
East    1/6/2018    1

West    2/3/2018    1
West    2/4/2018    1
West    2/5/2018    1

West    2/11/2018   1
West    2/12/2018   0
West    2/13/2018   1
West    2/14/2018   1

West    2/19/2018   1
West    2/20/2018   0
West    2/21/2018   1
West    2/22/2018   0
West    2/23/2018   1

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Вот как легко решить эту проблему с помощью предложения match_recognize (для которого требуется Oracle 12.1 или выше):

РЕДАКТИРОВАТЬ : Я пропустил версию Oracle OP, которая указана как 11g. Таким образом, это решение не поможет ему / ей; Я держу этот ответ, тем не менее, для тех, кто может найти это полезным в будущем.

select *
from   inputs
match_recognize(
  partition by region
  order by     dt
  all rows per match
  pattern      (a{3,})
  define       a as val = 1 or prev(val) = 1 and next(val) = 1
);

См. Мой другой ответ (с использованием метода tabibitosan) для входных данных в предложении WITH и для вывода (такой же, как в оригинальном сообщении).

0 голосов
/ 09 января 2019

Проблема усложняется требованием «маскировать» значение - 0 становится равным 1 при некоторых условиях. В противном случае это было бы прямым применением метода табибитозана. Более того, в конечном выводе вы хотите исходные значения, а не маскированные, поэтому мы должны быть осторожны с тем, что мы сохраняем и что отбрасываем на каждом шаге.

Вот один из способов решения проблемы. Обратите внимание, что DATE является ключевым словом Oracle, поэтому его не следует использовать в качестве имени столбца (он может не вызывать синтаксическую ошибку, но затрудняет понимание кода). Я не проверял, является ли VALUE также ключевым словом; просто для безопасности я изменил имена обоих столбцов на DT и VAL. (Как вы увидите, в моем коде я создаю столбцы GRP и CT для группы и количества соответственно; GROUP и COUNT являются ключевыми словами Oracle, поэтому применимо то же самое.)

with
  inputs(region, dt, val) as (
    select 'East', to_date('1/1/2018' , 'mm/dd/yyyy'), 1 from dual union all
    select 'East', to_date('1/2/2018' , 'mm/dd/yyyy'), 1 from dual union all
    select 'East', to_date('1/3/2018' , 'mm/dd/yyyy'), 0 from dual union all
    select 'East', to_date('1/4/2018' , 'mm/dd/yyyy'), 1 from dual union all
    select 'East', to_date('1/6/2018' , 'mm/dd/yyyy'), 1 from dual union all
    select 'East', to_date('1/7/2018' , 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('1/9/2018' , 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('1/10/2018', 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/3/2018' , 'mm/dd/yyyy'), 1 from dual union all
    select 'West', to_date('2/4/2018' , 'mm/dd/yyyy'), 1 from dual union all
    select 'West', to_date('2/5/2018' , 'mm/dd/yyyy'), 1 from dual union all
    select 'West', to_date('2/8/2018' , 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/9/2018' , 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/10/2018', 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/11/2018', 'mm/dd/yyyy'), 1 from dual union all
    select 'West', to_date('2/12/2018', 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/13/2018', 'mm/dd/yyyy'), 1 from dual union all
    select 'West', to_date('2/14/2018', 'mm/dd/yyyy'), 1 from dual union all
    select 'West', to_date('2/17/2018', 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/18/2018', 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/19/2018', 'mm/dd/yyyy'), 1 from dual union all
    select 'West', to_date('2/20/2018', 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/21/2018', 'mm/dd/yyyy'), 1 from dual union all
    select 'West', to_date('2/22/2018', 'mm/dd/yyyy'), 0 from dual union all
    select 'West', to_date('2/23/2018', 'mm/dd/yyyy'), 1 from dual
  )
, prep(region, dt, val, adj_val) as (
    select region, dt, val,
           case when val = 1
                or   lag(val)  over (partition by region order by dt) = 1
                     and
                     lead(val) over (partition by region order by dt) = 1
                then 1 else 0 end
    from   inputs
  )
, tabibitosan(region, dt, val, adj_val, grp) as (
    select region, dt, val, adj_val,
           row_number() over (partition by region order by dt)
           - row_number() over (partition by region, adj_val order by dt)
    from   prep
  )
, group_counts(region, dt, val, ct) as (
    select region, dt, val, count(*) over (partition by region, grp)
    from   tabibitosan
    where  adj_val = 1
  )
select   region, dt, val
from     group_counts
where    ct >= 3
order by region, dt
;

Выход:

REGION DT               VAL
------ --------- ----------
East   01-Jan-18          1
East   02-Jan-18          1
East   03-Jan-18          0
East   04-Jan-18          1
East   06-Jan-18          1
West   03-Feb-18          1
West   04-Feb-18          1
West   05-Feb-18          1
West   11-Feb-18          1
West   12-Feb-18          0
West   13-Feb-18          1
West   14-Feb-18          1
West   19-Feb-18          1
West   20-Feb-18          0
West   21-Feb-18          1
West   22-Feb-18          0
West   23-Feb-18          1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...