3

PARTITION BY OVER を使用して、特定の列で行を「グループ化」しようとしています。PARTITION の使用についてはある程度理解していますが、パーティションを日付で「ブロック」したいと考えています。たとえば、

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

そして、col1 でパーティション分割したいのですが、最後の A を最初の 2 つとは「異なる」ものにしたいのです。これは、日付が「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」の 2 つのシーケンスを分離できるようにグループ ID を割り当てることに戻りましたが、これは非常に遅いです。

ありがとう、

マーク。

4

4 に答える 4

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

次に、これらの null を埋めることができます。

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()による割り当てのケースですcol2grp

フィドル: http://sqlfiddle.com/#!4/4818c/1

于 2013-03-07T08:05:17.720 に答える
0

以下の私のアプローチを参照してください。これは、Dazzalの答えと似ていますが、ロジックが少し異なります。

SQLフィドル

ステップ1:

--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

ステップ3:

--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
于 2013-03-07T09:20:05.850 に答える
0

最初に、各レコードの GROUP_ID を見つけて、類似するすべての COL1 を異なるグループに並べ替える必要があります (それらの間にギャップがある場合)。次に、この GROUP_ID を OVER ステートメントで COL1 とともに使用します。

SQLFiddle デモ

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
于 2013-03-07T08:09:54.173 に答える
0

パーティションは必要ありません。日付を DD/MM/YYYY 形式に変換して並べ替える必要があります。または、必要に応じて、MM 部分で分割できます。これにより、01,02,03... が得られ、必要に応じて分割して簡単に数値に変換できます。しかし、これらすべてが必要なわけではありません... クエリを複雑にしないでください。常にシンプルに保ちます。外側のクエリは、日付を DD/MON/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
于 2013-03-07T14:53:44.530 に答える