2013-07-24 2 views
5

У меня есть следующий набор данных.Oracle Аналитические функции - сброс окошка оговорки

create table t1 (
    dept number, 
    date1 date 
); 

Table created. 

insert into t1 values (100, '01-jan-2013'); 
insert into t1 values (100, '02-jan-2013'); 
insert into t1 values (200, '03-jan-2013'); 
insert into t1 values (100, '04-jan-2013'); 
commit; 

Основная цель - создать столбец рангов, который сбрасывается каждый раз, когда изменяется отдел. Самый близкий столбец, который я могу использовать для предложения «partition by», - это dept, но это не даст мне желаемого результата.

SQL> select * from t1; 

     DEPT DATE1 
---------- --------- 
     100 01-JAN-13 
     100 02-JAN-13 
     200 03-JAN-13 
     100 04-JAN-13 

select dept, 
     date1, 
     rank() Over (partition by dept order by date1) rnk 
from t1 
order by date1; 

     DEPT DATE1   RNK 
---------- --------- ---------- 
     100 01-JAN-13   1 
     100 02-JAN-13   2 
     200 03-JAN-13   1 
     100 04-JAN-13   3 

Желаемый результат следующий. Последний rnk = 1 состоит в том, что запись Jan-04 является первой записью после изменения.

 DEPT DATE1   RNK 
---------- --------- ---------- 
     100 01-JAN-13   1 
     100 02-JAN-13   2 
     200 03-JAN-13   1 
     100 04-JAN-13   1 <<<---------- 

Любые указатели?

+1

+1. , , Вы включаете код для фактического тестирования того, что вы хотите знать. И примеры результатов. Могу ли я увеличить вдвое? –

+0

Спасибо Гордон. Это моя обычная жалоба с другими вопросами, я лучше следую тому, что я проповедую :) –

ответ

4

Это немного сложно. Вместо использования rank() или тому подобного, используйте lag(), чтобы увидеть, когда что-то изменится. Затем сделайте кумулятивную сумму флага.

select dept, date1, 
     CASE WHEN StartFlag = 0 THEN 1 
      ELSE 1+StartFlag+NVL(lag(StartFlag) over (order by date1),0) 
     END as rnk 
from (select t1.*, 
      (case when dept = lag(dept) over (order by date1) 
        then 1 
        else 0 
       end) as StartFlag 
     from t1 
    ) t1 
order by date1; 

Here является SQLFiddle.

EDIT:

Это Гордон редактирование моего собственного ответа. К сожалению. Исходный запрос был на 90%. Он идентифицировал группы , где цифры должны увеличиваться, но не назначали числа внутри групп. Я хотел бы сделать это с другим уровнем row_number() как в:

select dept, date1, 
     row_number() over (partition by dept, grp order by date1) as rnk 
from (select dept, date1, startflag, 
      sum(StartFlag) over (partition by dept order by date1) as grp 
     from (select t1.*, 
        (case when dept = lag(dept) over (order by date1) 
         then 0 
         else 1 
        end) as StartFlag 
      from t1 
      ) t1 
    ) t1 
order by date1; 

Таким образом, общая идея заключается в следующем. Сначала используйте lag(), чтобы определить, где начинается группа (т. Е. При изменении отдела с одной даты на другую). Затем присвойте им «групповой идентификатор», выполнив кумулятивную сумму. Это записи, которые должны быть перечислены. Последний шаг - перечислить их, используя row_number().

+0

Чтобы сделать работу с задержкой, я удалил раздел по делению во внутреннем запросе, и я вижу 0 и 1 как ожидалось, но сумма (Флаг) не дает конечного результата. Я создал здесь скрипт sql, если это поможет. http://sqlfiddle.com/#!4/0a9fe/7 –

+0

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

+0

На правильном пути я думаю, что это то, что нужно: http://www.sqlfiddle.com/#!4/fc339/14 –

2

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

select dept, date1, rank from t1 
model 
    dimension by (row_number() over(order by date1) as rn) 
    measures(1 as rank, dept, date1) 
    rules ( 
    rank[1] = 1, 
    rank[rn > 1] = 
    case dept[cv()] 
     when dept[cv()-1] then rank[cv()-1] + 1 
     else 1 
    end 
) 

http://www.sqlfiddle.com/#!4/fc339/132

+0

Спасибо, что напомнили мне, мне действительно нужно хорошо разбираться в положениях модели и ее использовании. :) –

0

Подход:

  1. Марка каждая строка с «номером строки» и «изменился» флаг
  2. высчитать окончательное «РНК» как разница между «номер строки» и максимальный предыдущий номер строки, который соответствует «измененной» строке.

Это похоже на ответ Гордона, но написанный с использованием CTE, который мне легче читать.

with cte as (
    select dept, date1, 
     row_number() over (order by date1) as row, 
     case when dept = (lag(dept) over (order by date1)) then 0 else 1 end as changed 
    from t1 
) 
select dept, date1, 
    row - max(case when changed = 1 then row else 1 end) over (order by date1) + 1 as rnk 
from cte 
order by date1 

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

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