0

これは、私がすでに尋ねた (そして回答した) ここでの質問と非常によく似ています:対象期間の開始と終了の識別 - oracle 10g sql

ただし、この場合に必要なものを達成する方法を見つけることができませんでした。次のようなデータがあります。

ID  Start            End    End Code        Worker ID
A   02/08/2003  23/01/2007  A               1
A   24/01/2007  17/11/2008  J               2
A   03/03/2009  20/10/2009  A               3
A   21/10/2009  08/03/2010  A               4
A   09/03/2010  29/07/2010  A               5
A   30/07/2010                              6

終了コード「A」はケースが再割り当てされたことを意味し、「J」はケースがクローズされたことを意味します。次のようなデータが必要です。

     ID Start             End   Worker IDs  End Worker
     A  02/08/2003  17/11/2008  1,2         2
     A  03/03/2009              3,4,5,6     6

すでに述べたように、これは以前に尋ねた質問と非常によく似ていますが、その場合、利用できる開始コードがありました。割り当ての開始日を特定する必要があると思います。それは、「J」コードを持つ割り当てに続く最初の日付か、最初の日付のいずれかですが、少し苦労しています。アドバイスをいただければ幸いです。参考までに、私のオラクルのバージョンは 10g、10.2.0.5.0 です。

編集: @Dazzal から提供された元のクエリに回答した回答を受け入れましたが、@Gordon Linoff の回答に基づいて新しい質問を投稿しました。これは私のニーズにより適していると思います。 https://stackoverflow.com/questions/13383560/grouping-data-oracle-sql-based-on-sum

4

2 に答える 2

1

ワーカー ID の順序付けが重要でない場合は、組み込みの集計関数を使用します。

SQL> select id, min(start_date), max(case when last_worker is not null then end_date end) end_date,
  2         wm_concat(worker_id) worker_ids, max(last_worker) last_worker
  3    from (select id, start_date, end_date, end_code, worker_id, case when end_code ='J' or end_date is null then worker_id end last_worker,
  4                 nvl(max(r) over (partition by id order by end_date nulls last), 1) r
  5    from (select t.*,
  6                  case
  7                    when lag(end_code, 1) over (partition by id order by end_date nulls last) = 'J' then
  8                     row_number() over(partition by id order by end_date nulls last)
  9                  end r
 10             from test t)
 11  )
 12  group by id, r;

I MIN(START END_DATE  WORKER_IDS           LAST_WORKER
- --------- --------- -------------------- -----------
A 02-AUG-03 17-NOV-08 1,2                            2
A 03-MAR-09           3,6,5,4                        6

そうですか、独自の集計関数を作成する必要があります。たとえば、10gで使用するものは次のとおりです。

SQL> select id, min(start_date), max(case when last_worker is not null then end_date end) end_date,
  2         stragg_num(stragg_num_typ(worker_id, ',', worker_id)) worker_ids, max(last_worker) last_worker
  3    from (select id, start_date, end_date, end_code, worker_id, case when end_code ='J' or end_date is null then worker_id end last_worker,
  4                 nvl(max(r) over (partition by id order by end_date nulls last), 1) r
  5    from (select t.*,
  6                  case
  7                    when lag(end_code, 1) over (partition by id order by end_date nulls last) = 'J' then
  8                     row_number() over(partition by id order by end_date nulls last)
  9                  end r
 10             from test t)
 11  )
 12  group by id, r;

I MIN(START END_DATE  WORKER_IDS           LAST_WORKER
- --------- --------- -------------------- -----------
A 02-AUG-03 17-NOV-08 1,2                            2
A 03-MAR-09           3,4,5,6                        6

SQL>

その定義は次のとおりです。

drop function stragg;
drop function stragg_num;
drop type string_agg_type;
drop type stragg_vc_tab;
drop type stragg_vc_typ;
drop type stragg_num_tab;
drop type stragg_num_typ;
create or replace type stragg_vc_typ as object
(
  value   varchar2(4000),
  delim   varchar2(10),
  rown    varchar2(4000)
);
/
create or replace type stragg_vc_tab
as table of stragg_vc_typ;
/
show errors type stragg_vc_tab
create or replace type stragg_num_typ as object
(
  value   varchar2(4000),
  delim   varchar2(10),
  rown    integer
);
/
show errors type stragg_num_typ
create or replace type stragg_num_tab
as table of stragg_num_typ;
/
show errors type stragg_num_tab


create or replace type string_agg_type as object
(
   total clob,
   delim   varchar2(10),
   data    stragg_num_tab,
   data2    stragg_vc_tab,

   static function
        ODCIAggregateInitialize(sctx IN OUT string_agg_type )
        return number,

   member function
        ODCIAggregateIterate(self IN OUT string_agg_type ,
                             value IN stragg_num_typ )
        return number,

   member function
        ODCIAggregateIterate(self IN OUT string_agg_type ,
                             value IN stragg_vc_typ )
        return number,

   member function
        ODCIAggregateTerminate(self IN string_agg_type,
                               returnValue OUT  varchar2,
                               flags IN number)
        return number,

   member function
        ODCIAggregateMerge(self IN OUT string_agg_type,
                           ctx2 IN string_agg_type)
        return number
);
/
show errors type string_agg_type
create or replace type body string_agg_type
is


static function ODCIAggregateInitialize(sctx IN OUT string_agg_type)
return number
is
begin
    sctx := string_agg_type( null, null, null, null );
    return ODCIConst.Success;
end;

member function ODCIAggregateIterate(self IN OUT string_agg_type,
                                     value IN stragg_num_typ )
return number
is
begin
    if (delim is null)
    then
      delim := value.delim;
    end if;
    if (data is null)
    then
      data := stragg_num_tab();
    end if;
    data.extend;
    data(data.last) := value;
    return ODCIConst.Success;
end;

member function ODCIAggregateIterate(self IN OUT string_agg_type,
                                     value IN stragg_vc_typ )
return number
is
begin
    if (delim is null)
    then
      delim := value.delim;
    end if;
    if (data2 is null)
    then
      data2 := stragg_vc_tab();
    end if;
    data2.extend;
    data2(data2.last) := value;
    return ODCIConst.Success;
end;

member function ODCIAggregateTerminate(self IN string_agg_type,
                                       returnValue OUT varchar2,
                                       flags IN number)
return number
is
  v_delim  varchar2(10);
begin
    if data is not null 
    then
      for r_item in (select d.value
                       from table(data) d
                      order by d.rown)
      loop
        returnValue := returnValue || v_delim || r_item.value;
        v_delim := self.delim;
      end loop;
    else
      for r_item in (select d.value
                       from table(data2) d
                      order by d.rown)
      loop
        returnValue := returnValue || v_delim || r_item.value;
        v_delim := self.delim;
      end loop;
    end if;
    return ODCIConst.Success;
end;

member function ODCIAggregateMerge(self IN OUT string_agg_type,
                                   ctx2 IN string_agg_type)
return number
is
begin
    self.total := self.total || ctx2.total;
    return ODCIConst.Success;
end;


end;
/
show errors type body string_agg_type
CREATE or replace FUNCTION stragg_num(input stragg_num_typ )
RETURN varchar2
PARALLEL_ENABLE AGGREGATE USING string_agg_type;
/

CREATE or replace FUNCTION stragg(input stragg_vc_typ )
RETURN varchar2
PARALLEL_ENABLE AGGREGATE USING string_agg_type;
/
于 2012-11-09T16:33:42.790 に答える
0

これは集合演算で行うことができます。以下は、ギャップがない期間、つまり終了コードを使用しない期間を示しています。関数を使用して、レコードが期間を開始するかどうかを決定しlagます。次に、累積合計を実行してグループ内のメンバーを識別し、集計してそれらをまとめます。

select groupnum, MIN(start) as start,
       (case when GroupSeqNum = NumInGroup then max(end) end) as end,
       listagg(WorkerId delimiter ',' order by start) as WorkerIds,
       (case when GroupSeqNum = NumInGroup then max(WorkerId) end) as EndWorker
from (select t.*,
             ROW_NUMBER() over (partition by id, groupnum order by start) as GroupSeqNum,
             COUNT(*) over (partition by id, groupnum) as NumInGroup     
      from (select t.*,
                   SUM(IsStart) over (partition by id order by start) as GroupNum
            from (select t.*,
                         (case when lag(end) over (partition by id order by start) = start - 1 then 0 else 1 end) as IsStart
                  from t
                 ) t
           ) t
    ) t

「J」コードで終わるグループを識別している場合は、IsStart の定義を次のように変更するだけです。

                     (case when lag(EndCode) over (partition by id order by start) = 'J' then 0 else 1 end) as IsStart
于 2012-11-09T17:02:22.507 に答える