Как использовать функцию Listagg Oracle с уникальным фильтром? [дубликат]

этот вопрос уже есть ответ здесь:

  • LISTAGG в Oracle для возврата различных значений 20 ответов

у меня есть такой стол:

group_id  name  
--------  ----
1         David
1         John
1         Alan
1         David
2         Julie
2         Charles

и я хочу следующий результат:

group_id  names
--------  -----
1         'Alan, David, John'
2         'Charles, Julie'

Я могу использовать следующий запрос:

select group_id, 
       listagg(name, ',') within group (order by name) as names
from demotable
group by group_id 

чтобы получить это (очень похоже результат):

group_id  names
--------  -----
1         'Alan, David, David, John'
2         'Charles, Julie'

любые идеи, как я могу фильтровать имена по уникальности в LISTAGG звонок?

7 ответов


У меня нет экземпляра 11g, доступного сегодня, но не могли бы вы использовать:

SELECT group_id,
       LISTAGG(name, ',') WITHIN GROUP (ORDER BY name) AS names
  FROM (
       SELECT UNIQUE
              group_id,
              name
         FROM demotable
       )
 GROUP BY group_id

супер простой ответ - решена!

select group_id, 
regexp_replace(
    listagg(name, ',') within group (order by name)
    ,'([^,]+)(,)*(,|$)', '')
from demotable
group by group_id;  

это работает только при указании разделителя на', ' не ', ' ie работает только без пробелов после запятой. Если вы хотите пробелы после запятой-вот пример того, как.

select 
replace(
    regexp_replace(
     regexp_replace('BBall, BBall, BBall, Football, Ice Hockey ',',\s*',',')            
    ,'([^,]+)(,)*(,|$)', '')
,',',', ') 
from dual

дает Ббол, Футбол, Хоккей

мой полный ответ здесь


create table demotable(group_id number, name varchar2(100));
insert into demotable values(1,'David');
insert into demotable values(1,'John');
insert into demotable values(1,'Alan');
insert into demotable values(1,'David');
insert into demotable values(2,'Julie');
insert into demotable values(2,'Charles');
commit;

select group_id, 
       (select listagg(column_value, ',') within group (order by column_value) from table(coll_names)) as names
from (
  select group_id, collect(distinct name) as coll_names 
    from demotable
    group by group_id 
)

GROUP_ID    NAMES
1   Alan,David,John
2   Charles,Julie

select group_id, 
       listagg(name, ',') within group (order by name) as names
       over (partition by group_id)   
from demotable
group by group_id 

в 11g вы можете использовать недокументированную функцию wm_concat следующим образом:

     select wm_concat(distinct name) as names from demotable group by group_id

Мне нужен был этот мир кода в качестве подзапроса с некоторым фильтром данных перед агрегацией на основе внешнего запроса most, но я не смог сделать это, используя выбранный код ответа, потому что этот фильтр должен идти во внутреннем наиболее выбранном (запрос третьего уровня), а параметры фильтра были во внешнем наиболее выбранном (запрос первого уровня), что дало мне ошибку ORA-00904:"TB_OUTERMOST"."Коль": недопустимый идентификатор поскольку ANSI SQL утверждает, что ссылки на таблицы (имена корреляции) ограничены только на один уровень глубже.

Мне нужно было решение без уровней подзапроса, и этот ниже отлично работал для меня:

with

demotable as
(
  select 1 group_id, 'David'   name from dual union all
  select 1 group_id, 'John'    name from dual union all
  select 1 group_id, 'Alan'    name from dual union all
  select 1 group_id, 'David'   name from dual union all
  select 2 group_id, 'Julie'   name from dual union all
  select 2 group_id, 'Charlie' name from dual
)

select distinct 
  group_id, 
  listagg(name, ',') within group (order by name) over (partition by group_id) names
from demotable
-- where any filter I want
group by group_id, name
order by group_id;

ниже не документируется и не рекомендуется oracle. и не может применяться в функции, показать ошибку

select wm_concat(distinct name) as names from demotable group by group_id

С уважением Зия!--2-->