这与我已经问过(并已回答)的问题非常相似:Identifying start and end of period covered - 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
答案 0 :(得分: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;
/
答案 1 :(得分: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