web-dev-qa-db-ja.com

一意のフィルターでOracleのLISTAGG関数を使用する方法は?

このようなテーブルがあります:

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呼び出しで一意性によって名前をフィルタリングする方法はありますか?

45
daveslab

現在利用可能な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
45
Ollie

超簡単な答え-解決済み!

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

これは、区切り文字を「、」ではなく「、」に指定した場合にのみ機能します。つまり、コンマの後のスペースがない場合にのみ機能します。コンマの後にスペースが必要な場合-ここに方法の例を示します。

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

bBall、サッカー、アイスホッケーを与えます

私の完全な答え ここ

16
ozmike
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
5
Michal Satny
select group_id, 
       listagg(name, ',') within group (order by name) as names
       over (partition by group_id)   
from demotable
group by group_id 
2
PJA

11gでは、文書化されていない関数wm_concatを次のように使用できます。

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

以下は文書化されておらず、Oracleによって推奨されていません。機能に適用できません、エラーを表示

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

よろしく

0
zia

最外部のクエリに基づいて集計する前に、データフィルターを含むサブクエリとしてこのコードの平和が必要でしたが、このフィルターは最も内側の選択(3番目のレベルのクエリ)に配置されるため、選択した回答コードを使用してこれを行うことができませんでしたANSI SQLがテーブル参照を示しているため、フィルターパラメーターが最も外側の選択(最初のレベルのクエリ)にあり、エラーが発生しましたORA-00904: "TB_OUTERMOST"。 "COL":無効な識別子 (相関名)のスコープは1レベルだけです。

私はサブクエリのレベルのないソリューションを必要としていましたが、これは私にとってはうまくいきました:

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;
0
Felypp Oliveira