是否可以从多行中构造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有帮助吗?

有帮助吗?

解决方案

有几种方法,具体取决于您的版本 - 查看 字符串聚合技术上的Oracle文档. 。一个非常常见的是使用 LISTAGG:

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

然后加入 A 挑选 pids 你要。

笔记: 盒子外面, LISTAGG 仅适用于 VARCHAR2 列。

其他提示

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

XMLAGG 您可以执行以下操作:

SELECT XMLAGG(XMLELEMENT(E,ename||',')).EXTRACT('//text()') "Result" 
FROM employee_names

这是什么

  • 放置 ename 列(与逗号连接) employee_names XML元素中的表(带有标签e)
  • 提取文字
  • 汇总XML(加入它)
  • 调用结果列“结果”

使用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.

我写了这个 这里. 。而且,如果您按照指向OTN-thread的链接,您会发现更多,包括性能比较。

Listagg 分析功能被引入 Oracle 11G版本2, ,使汇合很容易。如果您使用的是11G版本2,则应将此功能用于字符串聚合。有关字符串串联的更多信息,请参阅下面的URL。

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

字符串串联

正如大多数答案所暗示的那样, LISTAGG 是明显的选择。但是,一个令人讨厌的方面 LISTAGG 是,如果串联的总长度超过4000个字符(限制 VARCHAR2 在SQL)中,抛出了以下错误,在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;

以上会将输出限制为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 错误(无论如何,默认值)。

对于必须使用Oracle 9i(或更早)解决此问题的人,您可能需要使用SYS_CONNECT_BY_PATH,因为ListAgg不可用。

为了回答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;

在某些情况下,一个表中都包含键和值。可以在没有表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;

所有值都可以根据需要重新排序。可以按子句中的分区中重新排序个体的串联描述,并且可以按子句在最终顺序中重新排序的PID列表。


交替: 有时候,您想将整个表格中的所有值串联到一行中。

这里的关键思想是使用人为的价值来串联描述组。

在以下查询中,使用常数字符串'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;

单个串联描述可以按子句重新排序。

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

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

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

  2. 如果不需要排序,则收集最佳性能(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;

所有其他技术都较慢。

在运行选择查询之前,请运行以下内容:

SET SERVEROUT ON SIZE 6000

SELECT XMLAGG(XMLELEMENT(E,SUPLR_SUPLR_ID||',')).EXTRACT('//text()') "SUPPLIER" 
FROM SUPPLIERS;

我使用Listagg,但返回波斯字符串的字符串!

我的查询:

SELECT
 listagg(DESCRIPTION,' , ') within group (order by DESCRIPTION) 
FROM
B_CEREMONY

结果:

'A7'1 , ,4F

请帮我。

哇,这个解决方案有效:

SELECT listagg(convert(DESCRIPTION, 'UTF8', 'AL16UTF16'),' , ') within group 
(order by DESCRIPTION) 
FROM  B_CEREMONY;

尝试此代码:

 SELECT XMLAGG(XMLELEMENT(E,fieldname||',')).EXTRACT('//text()') "FieldNames"
    FROM FIELD_MASTER
    WHERE FIELD_ID > 10 AND FIELD_AREA != 'NEBRASKA';

在选择您想要的串联的位置,请调用SQL函数。

例如:

select PID, dbo.MyConcat(PID)
   from TableA;

然后对于SQL函数:

Function MyConcat(@PID varchar(10))
returns varchar(1000)
as
begin

declare @x varchar(1000);

select @x = isnull(@x +',', @x, @x +',') + Desc
  from TableB
    where PID = @PID;

return @x;

end

功能标题语法可能是错误的,但是原理确实有效。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top