如何在Oracle SQL中用LISTAGG获取去重的manager_id列表?
解决Oracle LISTAGG聚合重复manager_id的问题
好问题!这个场景在Oracle SQL里确实挺常见的——当你用LISTAGG直接聚合时,它会把每一行的manager_id都拼进去,哪怕同一个部门里同一个管理者对应多个员工,就会出现你遇到的重复串。下面给你几种实用的解决办法,覆盖不同Oracle版本:
1. Oracle 19c及以上版本:直接用LISTAGG的DISTINCT关键字
Oracle 19c开始给LISTAGG新增了DISTINCT支持,这是最简洁的方案,直接在函数里完成去重:
SELECT department_id, LISTAGG(DISTINCT manager_id, ' | ') WITHIN GROUP(ORDER BY manager_id) AS unique_managers FROM employees GROUP BY department_id;
这个写法和你原来统计count(distinct manager_id)的逻辑完全对应,一步到位,代码最干净。
2. 低版本Oracle(11g/12c等):先去重再聚合
如果你的Oracle版本还没到19c,那就先通过子查询或者CTE(公共表表达式)把每个部门下的唯一manager_id筛选出来,再对这个结果用LISTAGG:
-- 用CTE的写法,可读性更好 WITH distinct_managers AS ( SELECT DISTINCT department_id, manager_id FROM employees ) SELECT department_id, LISTAGG(manager_id, ' | ') WITHIN GROUP(ORDER BY manager_id) AS unique_managers FROM distinct_managers GROUP BY department_id;
或者用子查询嵌套的写法,适合更紧凑的代码风格:
SELECT department_id, LISTAGG(manager_id, ' | ') WITHIN GROUP(ORDER BY manager_id) AS unique_managers FROM ( SELECT DISTINCT department_id, manager_id FROM employees ) GROUP BY department_id;
这种方法兼容性最好,所有Oracle版本都能用,逻辑也很直观:先把重复的manager_id过滤掉,再做聚合拼接。
3. 低版本备选方案:用XMLAGG实现去重
还有一种利用XML函数的方法,适合需要更灵活处理字符串的场景,不过语法稍微复杂一点:
SELECT department_id, RTRIM(XMLAGG(XMLELEMENT(E, manager_id, ' | ') ORDER BY manager_id).EXTRACT('//text()'), ' | ') AS unique_managers FROM ( SELECT DISTINCT department_id, manager_id FROM employees ) GROUP BY department_id;
这里同样是先通过子查询去重,再用XMLAGG生成XML元素,最后提取文本并去掉末尾多余的分隔符。
总结一下:如果是19c及以上版本,优先用第一种LISTAGG(DISTINCT)的写法;低版本用第二种子查询/CTE的方法最容易理解和维护。
内容的提问来源于stack exchange,提问作者MrSir
相关产品推荐
相关产品推荐

