我有这样的表
+----------------------------+----------------------------+ | Customer_ref(varchar2(40)) | Event_source-varchar2(40)) | +----------------------------+----------------------------+ | ctx10000012 | 12474748,1247574,1247674 | | ctx10000013 | 12474748,12474749,12474750 | +----------------------------+----------------------------+
SELECT LISTAGG(EVENT_SOURCE, ', ') WITHIN GROUP(ORDER BY EVENT_SOURCE) from
( select distinct customer_ref, EVENT_SOURCE from CUSTEVENTSOURCE where customer_ref = Acc.Customer_ref AND END_DTM IS NULL)
表的输出应该像
+----------------------------+----------------------------+ | Customer_ref(varchar2(40)) | Event_source-varchar2(40)) | +----------------------------+----------------------------+ | ctx10000012 | 12474748,1247574,1247674 | | ctx10000013 | 12474748 - 12474750 | +----------------------------+----------------------------+
我如何在单选择查询中执行此操作(不使用with as select())。因为我在游标内使用此选择查询。
感谢您的帮助。
答案 0 :(得分:0)
此处没有内置功能可以帮助您。因此,自己编写一个名为ranges_string(或任何你喜欢的名字)的PL / SQL函数,将字符串从'1,2,3,5,7,8,9'转换为'1-3,5,7-9'(或者你需要它然后在你的select语句中调用它:
select ranges_string( listagg(event_source, ', ') within group(order by event_source) )
from
(
select distinct customer_ref, event_source from custeventsource
where customer_ref = acc.customer_ref and end_dtm is null
);
编辑:这是一个转换为范围的函数(将'1,2,3,6,7,8,10,12,13,14'转换为'1-3,6-8,10,12-例如14')。我没有花太多时间在它上面,所以当然不是很好,所以随意改变它: - )
create or replace function convert_ranges(vi_numbers varchar2) return varchar2 is
type table_of_integer is table of integer index by binary_integer;
v_numbers table_of_integer;
v_ranges varchar2(4000);
v_pos integer;
v_count integer;
begin
-- Tokenize
select regexp_substr(vi_numbers, '[^,]+', 1, level) as num
bulk collect into v_numbers
from dual
connect by regexp_substr(vi_numbers, '[^,]+', 1, level) is not null;
-- Collect
v_ranges := v_numbers(1);
v_pos := 2;
while v_pos <= v_numbers.count loop
v_count := 0;
while v_pos <= v_numbers.count and v_numbers(v_pos) = v_numbers(v_pos-1) + 1 loop
v_count := v_count + 1;
v_pos := v_pos + 1;
end loop;
if v_count > 0 then
v_ranges := v_ranges || '-' || v_numbers(v_pos-1);
end if;
if v_pos <= v_numbers.count then
v_ranges := v_ranges || ',';
v_ranges := v_ranges || v_numbers(v_pos);
v_pos := v_pos + 1;
end if;
end loop;
return v_ranges;
end convert_ranges;