2013-03-07 1 views
3

Я пытаюсь использовать PARTITION BY OVER для группировки строк по определенным столбцам. Я понимаю использование PARTITION несколько, однако я хочу «блокировать» разделы по дате. Например, если мы имеемOracle разделяет группу на дату на основе последовательности

|col1|col2  | 
| A |01/JAN/2012| 
| A |01/FEB/2012| 
| B |01/MAR/2012| 
| B |01/APR/2012| 
| A |01/MAY/2012| 

И я хочу разделить на col1, но я хочу, чтобы последние А быть «другими» от первых двух, как она отделена даты мудрых рядов на «B».

Если я использую;

SELECT ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY col2) AS RNUM, a.* 
FROM table1 a; 

Это даст;

|RNUM|col1|col2  | 
| 1| A |01/JAN/2012| 
| 2| A |01/FEB/2012| 
| 3| A |01/MAY/2012| 
| 1| B |01/MAR/2012| 
| 2| B |01/APR/2012| 

, но я действительно хочу;

|RNUM|col1|col2  | 
| 1| A |01/JAN/2012| 
| 2| A |01/FEB/2012| 
| 1| B |01/MAR/2012| 
| 2| B |01/APR/2012| 
| 1| A |01/MAY/2012| 

Возможно ли это с помощью PARTITION BY OVER? В настоящий момент я вернулся к использованию курсора для анализа данных и присвоения идентификатора группы, чтобы я мог разделить две последовательности «A», но это довольно медленно.

Thanks,

Оценка.

ответ

0

Сначала вы должны найти GROUP_ID для каждой записи, чтобы отсортировать все подобные COL1 к разным группам, если у них есть разрыв между.А затем использовать этот GROUP_ID в заявлении OVER с COL1:

SQLFiddle demo

SELECT ROW_NUMBER() OVER (PARTITION BY Group_id,col1 ORDER BY col2) AS RNUM, a3.* 
FROM 
(
select a1.*, 
     (select count(*) from t a2 where 
     a2.col1<>a1.col1 
     AND 
     a2.col2<a1.col2) as GROUP_ID 
from t a1 
) a3 

order by col2 
+0

Спасибо за этого @valex это сделал что я был после. Другие решения также работали, но это было наиболее кратким – Marcus

4

это возможно с парой аналитике:

select col1, col2, row_number() over (partition by grp order by col2) rnum 
    from (select col1, col2, max(grp) over(order by col2) grp 
      from (select col1, col2, 
         case 
         when lag(col1) over (order by col2) != col1 
         then 
          row_number() over (order by col2) 
         when row_number() over(order by col2) = 1 
         then 
          1 
         end grp 
        from data)); 

т.е.

сначала получить границы, где col1 изменения Сортировка по col2 дате:

SQL> select col1, col2, 
    2   case 
    3   when lag(col1) over (order by col2) != col1 
    4   then 
    5    row_number() over (order by col2) 
    6   when row_number() over(order by col2) = 1 
    7   then 
    8    1 
    9   end grp 
10 from data; 

C COL2    GRP 
- --------- ---------- 
A 01-JAN-12   1 
A 01-FEB-12 
B 01-MAR-12   3 
B 01-APR-12 
A 01-MAY-12   5 

мы можем заполнить те ноль:

SQL> select col1, col2, max(grp) over(order by col2) grp 
    2 from (select col1, col2, 
    3     case 
    4     when lag(col1) over (order by col2) != col1 
    5     then 
    6      row_number() over (order by col2) 
    7     when row_number() over(order by col2) = 1 
    8     then 
    9      1 
10     end grp 
11   from data); 

C COL2    GRP 
- --------- ---------- 
A 01-JAN-12   1 
A 01-FEB-12   1 
B 01-MAR-12   3 
B 01-APR-12   3 
A 01-MAY-12   5 

то его случай присвоения row_number() заказав по col2 и разбиением на grp

скрипку: http://sqlfiddle.com/#!4/4818c/1

0

Смотрите мой подход ниже, это simmilar ответить Dazzal, в немного другая логика:

SQL FIDDLE

Step1 :

--find the swhitches to new groups 
select col1, col2, 
    case when nvl(lag(col1) over (order by col2),sysdate) <> col1 then 1 end as new_grp 
    from data; 

COL1 COL2  NEW_GRP 
A January, 01 2012 1 
A February, 01 2012 (null) 
B March, 01 2012  1 
B April, 01 2012  (null) 
A May, 01 2012  1 

Шаг2:

--identify/mark the groups 

select col1, col2, sum(new_grp) over (order by col2) as grp 
from(
    select col1, col2, 
    case when nvl(lag(col1) over (order by col2),sysdate) <> col1 then 1 end as new_grp 
    from data) 
    ; 

COL1 COL2  NEW_GRP 
A January, 01 2012 1 
A February, 01 2012 1 
B March, 01 2012  2 
B April, 01 2012  2 
A May, 01 2012  3 

Step3:

--find the row_number within group 
select col1, col2, row_number() over(partition by grp order by col2) rn 
from(
    select col1, col2, sum(new_grp) over (order by col2) as grp 
    from(
    select col1, col2, 
     case when nvl(lag(col1) over (order by col2),sysdate) <> col1 then 1 end as new_grp 
    from data 
    ) 
); 

COL1 COL2  NEW_GRP 
A January, 01 2012 1 
A February, 01 2012 2 
B March, 01 2012  1 
B April, 01 2012  2 
A May, 01 2012  1 
0

Вам не нужно раздел. Вам необходимо конвертировать ваши даты в формат DD/MM/YYYY и заказывать их. Или, если необходимо, вы можете разделить на часть MM, которая дает вам 01,02,03 ... и может быть разделена и легко преобразована в номер, если это необходимо. Но вам не нужно все это ... Не затрудняйте свои запросы. Всегда держите его простым. Внешний запрос только переформатировать даты обратно в DD формате/ПН/YYYY:

SELECT val, to_char(to_date(dt, 'DD/MM/YYYY'), 'DD/MON/YYYY') formatted_date 
    FROM 
(-- Format your date to DD/MM/YYYY and order by it -- 
SELECT 'A' val, to_char(to_date('01/JAN/2012'), 'DD/MM/YYYY') dt FROM dual 
UNION 
SELECT 'A', to_char(to_date('01/FEB/2012'), 'DD/MM/YYYY') FROM dual 
UNION 
SELECT 'B',to_char(to_date('01/MAR/2012'), 'DD/MM/YYYY') FROM dual 
UNION 
SELECT 'B',to_char(to_date('01/APR/2012'), 'DD/MM/YYYY') FROM dual 
UNION 
SELECT 'A',to_char(to_date('01/MAY/2012'), 'DD/MM/YYYY') FROM dual 
ORDER BY 2 
) 
/

даты вашего упорядочены, как вы хотели, чтобы потом:

VAL FORMATTED_DATE 
------------------- 
A 01/JAN/2012 
A 01/FEB/2012 
B 01/MAR/2012 
B 01/APR/2012 
A 01/MAY/2012