SQL Query用于连接Oracle中多行的列值

jag*_*mot 149 sql oracle string-aggregation

是否可以构造SQL来连接多行的列值?

以下是一个例子:

表A.

PID
A
B
C

表B.

PID   SEQ    Desc

A     1      Have
A     2      a nice
A     3      day.
B     1      Nice Work.
C     1      Yes
C     2      we can 
C     3      do 
C     4      this work!

SQL的输出应该是 -

PID   Desc
A     Have a nice day.
B     Nice Work.
C     Yes we can do this work!

所以输出表的Desc列基本上是表B的SEQ值的串联?

有没有SQL的帮助?

Lou*_*nco 215

根据您的版本,有几种方法 - 请参阅有关字符串聚合技术oracle文档.一个非常常见的用途是LISTAGG:

SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description
FROM B GROUP BY pid;
Run Code Online (Sandbox Code Playgroud)

然后加入A挑选pids你想要的.

注意:开箱即用,LISTAGG仅适用于VARCHAR2列.

  • 使用wm_concat()for Oracle 10g以逗号分隔的序列号的升序连接文本,我们可以用其他东西分隔下行吗? (2认同)

Pet*_*ter 19

还有一个XMLAGG功能,适用于11.2之前的版本.因为WM_CONCAT由Oracle无证和不支持的,建议不要在生产系统中使用它.

有了XMLAGG你可以做到以下几点:

SELECT XMLAGG(XMLELEMENT(E,ename||',')).EXTRACT('//text()') "Result" 
FROM employee_names
Run Code Online (Sandbox Code Playgroud)

这是做什么的

  • 将表中的ename列(用逗号连接)employee_names放在xml元素中(带标记E)
  • 提取这个文本
  • 聚合xml(连接它)
  • 调用结果列"结果"


Rob*_*ijk 12

使用SQL模型子句:

SQL> select pid
  2       , ltrim(sentence) sentence
  3    from ( select pid
  4                , seq
  5                , sentence
  6             from b
  7            model
  8                  partition by (pid)
  9                  dimension by (seq)
 10                  measures (descr,cast(null as varchar2(100)) as sentence)
 11                  ( sentence[any] order by seq desc
 12                    = descr[cv()] || ' ' || sentence[cv()+1]
 13                  )
 14         )
 15   where seq = 1
 16  /

P SENTENCE
- ---------------------------------------------------------------------------
A Have a nice day
B Nice Work.
C Yes we can do this work!

3 rows selected.
Run Code Online (Sandbox Code Playgroud)

在这里写到了这个.如果你按照OTN线程的链接,你会发现更多,包括性能比较.


小智 9

LISTAGG分析功能在推出的Oracle 11g第2版,使它很容易聚集字符串.如果您使用的是11g第2版,则应使用此函数进行字符串聚合.有关字符串连接的更多信息,请参阅下面的url.

http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php

字符串连接


Kau*_*yak 7

正如大多数答案所暗示的那样,LISTAGG显而易见的选择.但是,令人讨厌的一个方面LISTAGG是,如果连接字符串的总长度超过4000个字符(VARCHAR2SQL中的限制),则抛出以下错误,这在Oracle版本中很难管理到12.1

ORA-01489:字符串连接的结果太长

在12cR2添加了一个新功能是ON OVERFLOW的条款LISTAGG.包含此子句的查询如下所示:

SELECT pid, LISTAGG(Desc, ' ' on overflow truncate) WITHIN GROUP (ORDER BY seq) AS desc
FROM B GROUP BY pid;
Run Code Online (Sandbox Code Playgroud)

以上将限制输出为4000个字符,但不会抛出 ORA-01489错误.

这些是ON OVERFLOW子句的一些附加选项:

  • ON OVERFLOW TRUNCATE 'Contd..' :这将显示'Contd..'在字符串的末尾(默认为...)
  • ON OVERFLOW TRUNCATE '' :这将显示4000个字符,没有任何终止字符串.
  • ON OVERFLOW TRUNCATE WITH COUNT:这将显示终止字符后结尾处的字符总数.例如: - ' ...(5512)'
  • ON OVERFLOW ERROR:如果您希望LISTAGG失败并出现 ORA-01489错误(无论如何都是默认值).


Mis*_*sho 6

  1. 如果必须排序,LISTAGG 可提供最佳性能(00:00:05.85)

    SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description FROM B GROUP BY pid;

  2. 如果不需要排序,COLLECT 可提供最佳性能(00:00:02.90):

    SELECT pid, TO_STRING(CAST(COLLECT(Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;

  3. 通过排序收集有点慢(00:00:07.08):

    SELECT pid, TO_STRING(CAST(COLLECT(Desc ORDER BY Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;

所有其他技术都较慢。


Jon*_*ndt 6

对于必须使用Oracle 9i(或更早版本)解决此问题的用户,由于LISTAGG不可用,您可能需要使用SYS_CONNECT_BY_PATH。

为了回答OP,以下查询将显示表A中的PID并连接表B中的所有DESC列:

SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
       FROM (
              SELECT a.pid, seq, description
              FROM table_a a, table_b b
              WHERE a.pid = b.pid(+)
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
GROUP BY pid
ORDER BY pid;
Run Code Online (Sandbox Code Playgroud)

在某些情况下,键和值都包含在一个表中。在没有表A且仅存在表B的情况下,可以使用以下查询:

SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
       FROM (
              SELECT pid, seq, description
              FROM table_b
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
GROUP BY pid
ORDER BY pid;
Run Code Online (Sandbox Code Playgroud)

所有值都可以根据需要重新排序。各个串联的描述可以在PARTITION BY子句中重新排序,而PID列表可以在最终的ORDER BY子句中重新排序。


或者:有时您可能希望将整个表中的所有值连接成一行。

这里的关键思想是为要连接的一组描述使用人工值。

在以下查询中,使用常量字符串“ 1”,但是任何值都可以使用:

SELECT SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY unique_id ORDER BY pid, seq) rnum, description
       FROM (
              SELECT '1' unique_id, b.pid, b.seq, b.description
              FROM table_b b
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1;
Run Code Online (Sandbox Code Playgroud)

各个串联的描述可以在PARTITION BY子句中重新排序。

此页面上的其他几个答案也提到了此非常有用的参考:https : //oracle-base.com/articles/misc/string-aggregation-techniques