首先還原listagg聚合之后出現重復數據的現象,打開plsql,執行如下sql:
1 select t.department_name depname, 2 t.department_key, 3 listagg(t.class_key, ',') within group(order by t.class_key) as class_keys 4 from V_YDXG_TEACHER_KNSRDGL t 5 where 1 = 1 6 group by t.department_key, t.department_name
運行結果:

如圖,listagg聚合之后很多重復數據,下面講解如何解決重復數據問題。
【a】 第一種方法: 使用wm_concat() + distinct去重聚合
1 --第一種方法: 使用wm_concat() + distinct去重聚合 2 select t.department_name depname, 3 t.department_key, 4 wm_concat(distinct t.class_key) as class_keys 5 from V_YDXG_TEACHER_KNSRDGL t 6 where 1 = 1 7 group by t.department_key, t.department_name

如上圖,listagg聚合之后沒有出現重復數據了。oracle官方不太推薦使用wm_concat()來進行聚合,能盡量使用listagg就使用listagg。
【b】第二種方法:使用正則替換方式去重(僅適用於oracle字符串大小比較小的情況)
1 --第二種方法:使用正則替換方式去重(僅適用於oracle字符串大小比較小的情況) 2 select t.department_name depname, 3 t.department_key, 4 regexp_replace(listagg(t.class_key, ',') within 5 group(order by t.class_key), 6 '([^,]+)(,\1)*(,|$)', 7 '\1\3') as class_keys 8 from V_YDXG_TEACHER_KNSRDGL t 9 group by t.department_key, t.department_name;

這種方式處理listagg去重問題如果拼接的字符串太長會報oracle超過最大長度的錯誤,只適用於數據量比較小的場景。
【c】第三種方法:先去重,再聚合(推薦使用)
1 --第三種方法:先去重,再聚合 2 select t.department_name depname, 3 t.department_key, 4 listagg(t.class_key, ',') within group(order by t.class_key) as class_keys 5 from (select distinct s.class_key, s.department_key, s.department_name 6 from V_YDXG_TEACHER_KNSRDGL s) t 7 group by t.department_key, t.department_name 8 9 --或者 10 select s.department_key, 11 s.department_name, 12 listagg(s.class_key, ',') within group(order by s.class_key) as class_keys 13 from (select t.department_key, 14 t.department_name, 15 t.class_key, 16 row_number() over(partition by t.department_key, t.department_name, t.class_key order by t.department_key, t.department_name) as rn 17 from V_YDXG_TEACHER_KNSRDGL t 18 order by t.department_key, t.department_name, t.class_key) s 19 where rn = 1 20 group by s.department_key, s.department_name; 21

推薦使用這種方式,先把重復數據去重之后再進行聚合處理。
