5

次のデータセットがあります。

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

ポインタはありますか?

4

3 に答える 3

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;

これがSQLFiddleです。

編集:

これはゴードンが私自身の答えを編集しています。おっとっと。元のクエリは 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()に、グループの開始位置 (つまり、ある日付から次の日付への部門の変更がある場所) を判別するために使用します。次に、累積合計を実行して、これらに「グループ ID」を割り当てます。これらは、列挙されるレコードです。最後のステップは、 を使用してそれらを列挙することrow_number()です。

于 2013-07-24T02:57:13.397 に答える
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

于 2013-07-24T07:13:23.340 に答える
0

アプローチは次のとおりです。

  1. 各行を「行番号」と「変更済み」フラグでマークします
  2. 「行番号」と「変更された」行に対応する以前の最大「行番号」との差として、最終的な「rnk」を計算します。

これはゴードンの答えに似ていますが、読みやすい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
于 2015-07-15T22:16:39.497 に答える