2016-09-28 9 views
2

Я пытаюсь решить проблему трендов при работе, очень похожей на приведенный ниже пример. Я думаю, что у меня есть метод, но я не знаю, как это сделать в SQL.Oracle SQL Trending MTD Data

Входные данные:

MTD   LOC_ID RAINED 
1-Apr-16 1  Y 
1-Apr-16 2  N 
1-May-16 1  N 
1-May-16 2  N 
1-Jun-16 1  N 
1-Jun-16 2  N 
1-Jul-16 1  Y 
1-Jul-16 2  N 
1-Aug-16 1  N 
1-Aug-16 2  Y 

Нужный выход:

MTD   LOC_ID RAINED TRENDS 
1-Apr-16 1  Y  New 
1-May-16 1  N  No Rain 
1-Jun-16 1  N  No Rain 
1-Jul-16 1  Y  Carryover 
1-Aug-16 1  N  No Rain 
1-Apr-16 2  N  No Rain 
1-May-16 2  N  No Rain 
1-Jun-16 2  N  No Rain 
1-Jul-16 2  N  No Rain 
1-Aug-16 2  Y  New 

Я пытаюсь произвести выходной сигнал из входного сигнала, на тренде МПД без зависимости Это. Таким образом, когда на вход добавляются новые месяцы, выход изменяется без редактирования запроса.

Логика для ТРЕНДОВ будет происходить на каждом уникальном LOC_ID. Тенденции будут иметь три значения: «Новый» в течение первого месяца RAINED - «Y», «Carryover» в последующие месяцы, когда RAINED «Y» и «No Rain» в любые месяцы, где RAINED «N».

Я хотел бы автоматизировать эту проблему, введя промежуточный шаг со списком. Например, для LOC_ID = «1»:

MTD   LOC_ID RAINED PREV_RAINED 
1-Apr-16 1  Y  (null)/0/(I don't care) 
1-May-16 1  N  Y 
1-Jun-16 1  N  Y;N 
1-Jul-16 1  Y  Y;N;N 
1-Aug-16 1  N  Y;N;N;Y 

Таким образом, для получения «Тренды» в выводе, я могу сказать:

case when RAINED = 'Y' then 
    case when not regexp_like(PREV_RAINED, 'Y', 'i') then 
     'New' 
    else 
     'Carryover' 
    end 
else 
    'No Rain' 
end as TRENDS 

Моя проблема в том, что я не знаю, как для создания PREV_RAINED для каждого уникального LOC_ID. У меня есть ощущение, что ему нужно комбинировать LAG() и раздел по порядку LOC_ID по MTD, но количество лаг, которое мне нужно сделать, зависит от каждого месяца.

Есть ли простой способ произвести PREV_RAINED или более простой способ решить мою общую проблему при сохранении автоматизации каждый месяц?

Спасибо за чтение всего этого! :)

+1

В примере, является ли тенденция для loc_id = 2 правильной? он шел в мае, но не в апреле, поэтому я ожидал нового в мае. Я ошибаюсь? – Aleksej

+0

Какая версия Oracle?В 12c вы можете использовать MATCH_RECOGNIZE. – mathguy

+0

@Aleksej Вы правы, но я испортил ввод в моем примере. Я отредактировал его правильно. –

ответ

1

В нижнем SQL есть две части.

(i) Calculating the ROWNUMBER value for rained attribute at loc_id,rained level. 
(ii) Get the count at partition level loc_id,rained. 

Вычислив два вышеизложенных, мы можем написать логику CASE WHEN для расчета тенденций, основанных на ваших требованиях.

SELECT mtd, 
     loc_id, 
     rained, 
     CASE WHEN rained = 'N' THEN 'No Rain' 
      WHEN rained = 'Y' AND rn = 1 THEN 'New' 
      ELSE 'Carry Over'  
     END AS Trends  
    FROM 
     ( 
      SELECT mtd, 
        loc_id, 
        rained,     
        ROW_NUMBER() OVER (PARTITION BY loc_id,rained ORDER BY mtd) AS rn, 
        COUNT(*) OVER (PARTITION BY loc_id,rained) AS count_locid_rained    
       FROM INPUT 
       ORDER BY loc_id,mtd,rained,rn 
     ) X; 
+0

Дайте мне шанс, чтобы выстрелить. Я дам вам знать, как это происходит. Спасибо! –

+0

Это очень близко к тому, что мне нужно. Тем не менее, я обнаружил, что в некоторых случаях новый флаг неправильно помечен, потому что COUNT_LOCID_RAINED неверен. Я отвечу детали в ответ. Когда вы рассчитываете на уровень раздела loc_id, дождь и помещаете его в ввод, на какой счет вы возвращаетесь? –

+0

Рассмотрим новый LOC_ID, 3. подзапрос для LOC_ID 3 возвращается: МТД LOC_ID лил PREV_RAINED COUNT_LOCID_RAINED 01-АПР-16 \t \t 3 н \t 01-May-16 \t \t 3 п \t п 01-JUN-16 \t у п 01-июль-16 \t \t 3 п \t \t у 3 01-августа-16 \t \t 3 у \t n Это испортило поле трендов, потому что COUNT_LOCID_RAINED неверно. Основной запрос будет работать, если COUNT_LOCID_RAINED был –

1

Вот решение для более старых версий. Предложение WITH для входных данных; решение начинается сразу после предложения WITH.

Теперь я буду работать над решением MATCH_RECOGNIZE, я могу добавить его к этому ответу.

with 
    input_data (mtd, loc_id, rained) as (
     select to_date('1-Apr-16', 'dd-Mon-rr'), 1, 'Y' from dual union all 
     select to_date('1-Apr-16', 'dd-Mon-rr'), 2, 'N' from dual union all 
     select to_date('1-May-16', 'dd-Mon-rr'), 1, 'N' from dual union all 
     select to_date('1-May-16', 'dd-Mon-rr'), 2, 'N' from dual union all 
     select to_date('1-Jun-16', 'dd-Mon-rr'), 1, 'N' from dual union all 
     select to_date('1-Jun-16', 'dd-Mon-rr'), 2, 'N' from dual union all 
     select to_date('1-Jul-16', 'dd-Mon-rr'), 1, 'Y' from dual union all 
     select to_date('1-Jul-16', 'dd-Mon-rr'), 2, 'N' from dual union all 
     select to_date('1-Aug-16', 'dd-Mon-rr'), 1, 'N' from dual union all 
     select to_date('1-Aug-16', 'dd-Mon-rr'), 2, 'Y' from dual 
    ) 
select mtd, loc_id, rained, 
     case rained when 'N' then 'No Rain' 
        else case when rn = 1 then 'New' 
             else 'Carryover' end 
        end as trends 
from (select mtd, loc_id, rained, 
       row_number() over (partition by loc_id, rained order by mtd) rn 
     from input_data 
) 
order by loc_id, mtd 
; 

Выход

MTD      LOC_ID RAINED TRENDS 
------------------- ---------- ------ --------- 
01/04/2016 00:00:00   1  Y New  
01/05/2016 00:00:00   1  N No Rain 
01/06/2016 00:00:00   1  N No Rain 
01/07/2016 00:00:00   1  Y Carryover 
01/08/2016 00:00:00   1  N No Rain 
01/04/2016 00:00:00   2  N No Rain 
01/05/2016 00:00:00   2  N No Rain 
01/06/2016 00:00:00   2  N No Rain 
01/07/2016 00:00:00   2  N No Rain 
01/08/2016 00:00:00   2  Y New  

10 rows selected 
+0

Спасибо! Я бы хотел избежать того, чтобы сделать что-то похожее на ваш первый ответ, потому что он требует редактирования запроса каждый раз, когда добавляется новый месяц. Я бы хотел, чтобы запрос сам настраивался на новые данные. –

+0

@ RyanBarker - ?? Какая часть запроса требует редактирования при добавлении новых месяцев? Надеюсь, вы не говорите о статье WITH; как я уже сказал, решение НЕ ВКЛЮЧАЕТ ЭТО. Удалите его и используйте остальные ('select mtd, ...' до конца) в вашей таблице (используя фактические имена таблиц и столбцов); когда добавляется больше строк, запрос должен работать без каких-либо изменений. – mathguy

+0

Мои извинения. Я неправильно понял, что вы сказали. Ваше решение великолепно и прекрасно работает. Спасибо за предоставление этого и снова, я приношу свои извинения за свое первоначальное недоразумение. –

1

Решение с использованием MATCH_RECOGNIZE (для Oracle 12c только). Проверьте различные решения на вашем наборе данных; Мне говорят, что MATCH_RECOGNIZE может быть значительно быстрее, чем другие решения, но это зависит от многих факторов.

select loc_id, mtd, rained, trends 
from input_data 
    match_recognize (
    partition by loc_id, rained 
    order by  mtd 
    measures  mtd as mtd, 
       case when rained = 'N' then 'No Rain' 
         else case when match_number() = 1 then 'New' else 'Carryover' end 
         end as trends 
    pattern (a) 
    define a as 0 = 0 
) 
order by loc_id, mtd; 

 Смежные вопросы

  • Нет связанных вопросов^_^