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”代码的分配之后的第一个日期,要么只是最早的日期,但我有点挣扎。任何建议表示赞赏!作为参考,我的oracle版本是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 回答