在 Oracle 中连接 SQL 查询的结果

Posted

技术标签:

【中文标题】在 Oracle 中连接 SQL 查询的结果【英文标题】:Concatenate results from a SQL query in Oracle 【发布时间】:2012-12-23 23:12:56 【问题描述】:

我在表格中有这样的数据

NAME PRICE
A    2
B    3
C    5
D    9
E    5

我想在一行中显示所有值;例如:

A,2|B,3|C,5|D,9|E,5|

我将如何在 Oracle 中进行查询以提供这样的字符串?我不需要将它编程为某种东西;我只是想要一种方法让该行出现在结果中,以便我可以将其复制并粘贴到 Word 文档中。

我的 Oracle 版本是 10.2.0.5。

【问题讨论】:

复制粘贴到另一个单词中? Oracle 数据库 10g 第 2 版:10.2.0.5 +1 的问题,这超出了listagg.... @bonCodigo; OP 不能使用 LISTAGG() 因为这不是 11g,但是,它并没有超出能力范围:select listagg(name || ',' || price, '|') within group ( order by name ) from TABLE @Ben 感谢分享。好吧,当我使用 11g 时,我使用了 Xmlagg 的不同路径。任何改进它的想法.. 【参考方案1】:

-- Oracle 10g --

SELECT deptno, WM_CONCAT(ename) AS employees
  FROM   scott.emp
GROUP BY deptno;

Output:
     10  CLARK,MILLER,KING
     20  SMITH,FORD,ADAMS,SCOTT,JONES
     30  ALLEN,JAMES,TURNER,BLAKE,MARTIN,WARD

【讨论】:

这很好用,而且很容易记住如何使用。您可以使用WM_CONCAT(distinct ename) 丢弃重复项,但我怀疑您是否可以对它们进行排序。而且,不幸的是,它不是officially documented。 问题不同【参考方案2】:

我知道这有点晚了,但试试这个:

SELECT LISTAGG(CONCAT(CONCAT(NAME,','),PRICE),'|') WITHIN GROUP (ORDER BY NAME) AS CONCATDATA
FROM your_table

【讨论】:

OP 在 10g 上,listagg() 在 11g 中引入。但是这个答案使整篇文章更好地总结了字符串聚合技术。【参考方案3】:

通常当我快速需要类似的东西并且我想在不使用 PL/SQL 的情况下继续使用 SQL 时,我会使用类似于以下 hack 的东西:

select sys_connect_by_path(col, ', ') as concat
from
(
  select 'E' as col, 1 as seq from dual
  union
  select 'F', 2 from dual
  union
  select 'G', 3 from dual
)
where seq = 3
start with seq = 1
connect by prior seq+1 = seq

这是一个分层查询,使用“sys_connect_by_path”特殊函数,旨在获取从父级到子级的“路径”。

我们正在做的是模拟 seq=1 的记录是 seq=2 的记录的父级,因此是第四个,然后获取最后一个子记录的完整路径(在这种情况下,记录 seq = 3 ),这将有效地串联所有“col”列

适应您的情况:

select sys_connect_by_path(to_clob(col), '|') as concat
from
(
  select name || ',' || price as col, rownum as seq, max(rownum) over (partition by 1) as max_seq
  from
  (
   /* Simulating your table */
    select 'A' as name, 2 as price from dual
    union
    select 'B' as name, 3 as price from dual
    union
    select 'C' as name, 5 as price from dual
    union
    select 'D' as name, 9 as price from dual
    union
    select 'E' as name, 5 as price from dual
  )
)
where seq = max_seq
start with seq = 1
connect by prior seq+1 = seq

结果是:|A,2|B,3|C,5|D,9|E,5

【讨论】:

【参考方案4】:

在 Oracle 10g 中,您不能使用出色的 listagg()。但是,还有许多其他string aggregation techniques。

没有特别需要所有复杂的东西。假设如下表

create table a ( NAME varchar2(1), PRICE number);
insert all
into a values ('A',    2)
into a values ('B',    3)
into a values ('C',    5)
into a values ('D',    9)
into a values ('E',    5)
select * from dual

不支持的函数wm_concat应该足够了:

select replace(replace(wm_concat (name || '#' || price), ',', '|'), '#', ',')
  from a;

REPLACE(REPLACE(WM_CONCAT(NAME||'#'||PRICE),',','|'),'#',',')
--------------------------------------------------------------------------------
A,2|B,3|C,5|D,9|E,5

但是,您也可以更改 Tom Kyte 的 stragg(也在上面的链接中),使其不使用替换功能。

【讨论】:

您正在使用wm_concat,太好了,请对我的回答发表评论。 我会测试一下你的【参考方案5】:

这是另一种方法,使用model 子句:

-- sample of data from your question
with t1(NAME1, PRICE) as(
   select 'A',    2 from dual union all
   select 'B',    3 from dual union all
   select 'C',    5 from dual union all
   select 'D',    9 from dual union all
   select 'E',    5 from dual
) -- the query
 select Res
  from (select name1
             , price
             , rn
             , res
         from t1
         model
         dimension by (row_number() over(order by name1) rn)
         measures (name1, price, cast(null as varchar2(101)) as res)
         (res[rn] order by rn desc = name1[cv()] || ',' || price[cv()] || '|' ||  res[cv() + 1])
       )
where rn = 1  

结果:

RES
----------------------
A,2|B,3|C,5|D,9|E,5| 

SQLFiddle Example

【讨论】:

【参考方案6】:

类似以下的东西,效率极低且未经测试。

    create function foo returning varchar2  as  
    (    
        declare bar varchar2(8000) --arbitrary number
        CURSOR cur IS
        SELECT name,price  
        from my_table  
        LOOP

    FETCH cur INTO r;

    EXIT WHEN cur%NOTFOUND;

       bar:= r.name|| ',' ||r.price || '|'

  END LOOP;  
  dbms_output.put_line(bar);
       return bar
    )  

【讨论】:

FETCH cur INTO r; 是做什么的? 将定义为curcursor 的结果放入名为r 的变量中。请注意我如何连接 bar 并通过 r.namer.price 引用您的列 当我做那个函数时,我如何执行它?我只是在 sql 查询窗口中运行该函数吗? @Ramie in sql developer 你可以右键运行函数。 我可以更改 varchar2 中的数字吗,因为我运行了您的查询,它说它已完成执行但没有结果。创建函数 f323oo 返回 varchar2 为 ( 声明 bar varchar2(8000) -- 任意数字 CURSOR cur IS SELECT CURRENCY, ONE from mkt.view_me LOOP FETCH cur INTO r; EXIT WHEN cur%NOTFOUND; bar:= r.CURRENCY|| ', ' ||r.ONE || '|' END LOOP; return bar )【参考方案7】:

使用 xmlagg 设法到达这里:使用 sql fiddle 中的 oracle 11G。

数据表:

COL1    COL2    COL3
1       0       0
1       1       1
2       0       0
3       0       0
3       1       0


SELECT
    RTRIM(REPLACE(REPLACE(
      XMLAgg(XMLElement("x", col1,',', col2, col3)

ORDER BY col1), '<x>'), '</x>', '|')) AS COLS
  FROM ab
;

结果:

COLS
1,00| 3,00| 2,00| 1,11| 3,10|

* SQLFIDDLE DEMO

Reference to read on XMLAGG

【讨论】:

@Woot4Moo 这就是为什么我说我只能走到这里。我没有发布赞成票,而是发布了另一种方法,如果可能的话。但是没想到会投反对票...:$ 我想这就是生活。我觉得这是值得一票的,因为它没有提供关于 XMLAgg 的太多细节以及这是如何有效的 @WootMoo 我不认为这是我的回答是错误的。我刚刚错过了 | 作为分隔符。我使用了不同的样本数据,但我的逻辑是正确的。 @Ramie 请看一下这个答案。它也支持10g。性能方面,它非常快。 让它与 2 列一起工作并对其进行不良测试,这样我就可以替换变量

以上是关于在 Oracle 中连接 SQL 查询的结果的主要内容,如果未能解决你的问题,请参考以下文章

sql server2005远程连接oracle11g查询结果中文乱码,怎么解决?

oracle中sql语句小练习(使用连接查询)

SQL - oracle - 如何从连接结果中选择特定部门

Oracle查询出两个字段连接成一个字段..中间有符号隔开

Oracle SQL 查询(左外连接)

在Oracle SQL中连接字符串之间没有空格?