使用 xmlagg 函数的 SQL 多 SELECT 查询 - 未以所需方式提取数据

Posted

技术标签:

【中文标题】使用 xmlagg 函数的 SQL 多 SELECT 查询 - 未以所需方式提取数据【英文标题】:SQL multiple SELECT query with xmlagg function- Data not pulled in the required fashion 【发布时间】:2012-06-19 16:01:33 【问题描述】:

我在 Oracle 中的数据是这样的

NAME | DEP_VALUE | ID_DEP

Amy     1         AA1234
Bob     2         BB4321
Clara   1         CC5678
Clara   2         CC7890
John    1         JJ6543
John    2         JJ7865
John    3         JJ7654
Tom     1         TT0987
Tom     2         TT6541
Tom     3         TT4087
Tom     4         TT3409

我需要以这种方式提取数据

NAME  | DEP_VALUE |  ID_DEP

Amy     1         AA1234
Bob     2         BB4321
Clara   1;2       CC5678;CC7890
John    1;2;3     JJ6543;JJ7865;JJ7654
Tom     1;2;3;4   TT0987;TT6541;TT4087;TT3409

我的查询如下

SELECT name,
   Rtrim(Xmlagg (Xmlelement (e, dep_value
                                || ';')).extract  ( '//text()' ), ','),
   Rtrim(Xmlagg (Xmlelement (e, id_dep
                                || ';')).extract  ( '//text()' ), ',')
FROM   (SELECT emp_name,
           dep.dep_value,
           dep.id_dep
    FROM   emp
           inner join dep
                   ON emp.name = dep.name
    WHERE  id_name IN (SELECT name
                       FROM   altname
                       WHERE  id_emp IN (SELECT id_emp
                                         FROM   cnames
                                         WHERE  emp_lvl LIKE '%GGG%')))
    GROUP  BY name,
      dep_value  

显示的结果是

NAME  | DEP_VALUE |  ID_DEP

Amy     1;         AA1234;
Bob     2;         BB4321;
Clara   1;         CC5678;
Clara   2;         CC7890;
John    1;         JJ6543;
John    2;         JJ7865;
John    3;         JJ7654;
Tom     1;         TT0987;
Tom     2;         TT6541;
Tom     3;         TT4087;
Tom     4;         TT3409;

如何提取第二张表中的数据?我的 sql 查询中的错误是什么?

【问题讨论】:

【参考方案1】:

听起来你想GROUP BY name而不是GROUP BY name, dep_value

SELECT name,
   Rtrim(Xmlagg (Xmlelement (e, dep_value
                                || ';')).extract  ( '//text()' ), ';'),
   Rtrim(Xmlagg (Xmlelement (e, id_dep
                                || ';')).extract  ( '//text()' ), ';')
FROM   (SELECT emp_name,
           dep.dep_value,
           dep.id_dep
    FROM   emp
           inner join dep
                   ON emp.name = dep.name
    WHERE  id_name IN (SELECT name
                       FROM   altname
                       WHERE  id_emp IN (SELECT id_emp
                                         FROM   cnames
                                         WHERE  emp_lvl LIKE '%GGG%')))
    GROUP  BY name

【讨论】:

还有一件事。在上面的查询中,“extract('//text()'),',')”中的部分实际上应该是“extract('//text()'),';')”。否则 id_dep 将看起来如JJ6543;JJ7865;JJ7654;而不是 JJ6543;JJ7865;JJ7654。会有一个额外的“;”结果。 有关确保dep_value 按顺序聚合的方法,请参阅this question。【参考方案2】:

只是为了提供对 xmlagg 的进一步解释,并在 Oracle 11g 中添加另一个选项。

http://www.dba-oracle.com/t_display_multiple_column_values_same_rows.htm

select
  deptno,
  listagg (ename, ',') 
WITHIN GROUP 
(ORDER BY ename) enames
FROM 
  emp
GROUP BY 
   deptno
/ 

输出:

DEPTNO ENAMES                                            
---------- --------------------------------------------------
    10 CLARK,KING,MILLER                                 
    20 ADAMS,FORD,JONES,SCOTT,SMITH                
    30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD 

【讨论】:

【参考方案3】:

尝试这样更简单

select NAME,replace(wm_concat(DEP_VALUE),',',';') as DEP_VALUE, replace(wm_concat(ID_DEP),',',';') as ID_DEP from yourtable 
where dep_value<2000 group by NAME

注意:你需要限制你的 dep_value 长度,你可以做出你的假设,因为你不能让你的字符串结果变长,希望这对你的工作有所帮助

【讨论】:

wm_concat 是做什么的 不要使用WM_CONCAT,它是无证的,并且已从更高版本的Oracle中删除。

以上是关于使用 xmlagg 函数的 SQL 多 SELECT 查询 - 未以所需方式提取数据的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Oracle 11g 中的 XMLAGG 函数序列化树数据而不是重复的 XML 标记,嵌套结构?

oracle聚合函数XMLAGG用法简介

oracle行转列,列转行函数的使用(listagg,xmlagg)

使用 PL/SQL 创建 XML

在单个表中使用XMLAGG的后台处理空间问题

将“LISTAGG”转换为“XMLAGG”