SQL查询到来自Oracle中多个行的连接列值

发布于 2025-02-05 15:45:41 字数 448 浏览 2 评论 0 原文

是否可以从 多行?

以下是一个示例:

表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!

输出应为 -因此,基本上,用于OUT PUT表的desc列是从表B中对SEQ值的串联?

SQL有帮助吗?

Would it be possible to construct SQL to concatenate column values from
multiple rows?

The following is an example:

Table A

PID
A
B
C

Table 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!

Output of the SQL should be -

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

So basically the Desc column for out put table is a concatenation of the SEQ values from Table B?

Any help with the SQL?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

狼性发作 2025-02-12 15:45:42

有几种方式,具体取决于您拥有的版本 - 请参阅。一个非常常见的是使用

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

然后加入 a 以挑选您想要的 pids

注意:开箱即用, listAgg 仅与 varchar2 列正确使用。

There are a few ways depending on what version you have - see the oracle documentation on string aggregation techniques. A very common one is to use LISTAGG:

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

Then join to A to pick out the pids you want.

Note: Out of the box, LISTAGG only works correctly with VARCHAR2 columns.

很糊涂小朋友 2025-02-12 15:45:42

还有一个 xmlagg 函数,该功能可在11.2之前的版本上使用。因为 wm_concat 无证件且无证件且无需由Oracle置于Oracle 它在生产系统中。

使用 xmlagg 您可以执行以下操作:

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

  • 雇用> lighteee_names 表中放置 ename column的值(与逗号串联)的值在XML元素(带有标签e)中
  • 提取此汇总的文本
  • XML(Concatenate it)
  • 调用结果列“结果”

There's also an XMLAGG function, which works on versions prior to 11.2. Because WM_CONCAT is undocumented and unsupported by Oracle, it's recommended not to use it in production system.

With XMLAGG you can do the following:

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

What this does is

  • put the values of the ename column (concatenated with a comma) from the employee_names table in an xml element (with tag E)
  • extract the text of this
  • aggregate the xml (concatenate it)
  • call the resulting column "Result"
不羁少年 2025-02-12 15:45:42

带有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的链接,您会发现更多内容,包括性能比较。

With SQL model clause:

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.

I wrote about this here. And if you follow the link to the OTN-thread you will find some more, including a performance comparison.

有深☉意 2025-02-12 15:45:42

listAgg 分析功能是在 oracle 11g版本2 中引入的,这使得汇总字符串非常容易。
如果您使用的是11G版本2,则应将此功能用于字符串聚合。
有关字符串串联的更多信息,请参阅下面的URL。

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

string confenation

The LISTAGG analytic function was introduced in Oracle 11g Release 2, making it very easy to aggregate strings.
If you are using 11g Release 2 you should use this function for string aggregation.
Please refer below url for more information about string concatenation.

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

String Concatenation

半山落雨半山空 2025-02-12 15:45:42

正如大多数答案所暗示的那样, listAgg 是显而易见的选项。但是, listAgg 的一个令人讨厌的方面是,如果串联字符串的总长度超过4000个字符( varchar2 in SQL中的限制),则会抛出以下错误,这很难在Oracle版本中管理至12.1

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

12cr2中添加的新功能是 listagg 的子句。
包括此子句在内的查询看起来像:

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

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

这些是 on vollflflow 子句:上的的其他选项:

  • 溢出截断'contd ..':这将显示'contd ..'
    字符串的结尾(默认为 ...
  • 在溢出截断上'':这将显示4000个字符
    没有任何终止字符串。
  • 在用计数截断上溢出:这将显示总计
    终止字符后末尾的字符数。
    例如: - ' ...(5512)'
  • 在溢出错误上:如果您期望 listagg
    ORA-01489 错误(无论如何默认)。

As most of the answers suggest, LISTAGG is the obvious option. However, one annoying aspect with LISTAGG is that if the total length of concatenated string exceeds 4000 characters( limit for VARCHAR2 in SQL ), the below error is thrown, which is difficult to manage in Oracle versions upto 12.1

ORA-01489: result of string concatenation is too long

A new feature added in 12cR2 is the ON OVERFLOW clause of LISTAGG.
The query including this clause would look like:

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

The above will restrict the output to 4000 characters but will not throw the ORA-01489 error.

These are some of the additional options of ON OVERFLOW clause:

  • ON OVERFLOW TRUNCATE 'Contd..' : This will display 'Contd..' at
    the end of string (Default is ... )
  • ON OVERFLOW TRUNCATE '' : This will display the 4000 characters
    without any terminating string.
  • ON OVERFLOW TRUNCATE WITH COUNT : This will display the total
    number of characters at the end after the terminating characters.
    Eg:- '...(5512)'
  • ON OVERFLOW ERROR : If you expect the LISTAGG to fail with the
    ORA-01489 error ( Which is default anyway ).
桃扇骨 2025-02-12 15:45:42

对于那些必须使用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.com/articles/misc/misc/misc/string-string-string-string-aggregation-techniques

For those who must solve this problem using Oracle 9i (or earlier), you will probably need to use SYS_CONNECT_BY_PATH, since LISTAGG is not available.

To answer the OP, the following query will display the PID from Table A and concatenate all the DESC columns from Table 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 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;

There may also be instances where keys and values are all contained in one table. The following query can be used where there is no Table A, and only Table B exists:

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;

All values can be reordered as desired. Individual concatenated descriptions can be reordered in the PARTITION BY clause, and the list of PIDs can be reordered in the final ORDER BY clause.


Alternately: there may be times when you want to concatenate all the values from an entire table into one row.

The key idea here is using an artificial value for the group of descriptions to be concatenated.

In the following query, the constant string '1' is used, but any value will work:

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;

Individual concatenated descriptions can be reordered in the PARTITION BY clause.

Several other answers on this page have also mentioned this extremely helpful reference:
https://oracle-base.com/articles/misc/string-aggregation-techniques

郁金香雨 2025-02-12 15:45:42
  1. Listagg如果排序为必须(00:00:05.85)

    ,则提供最佳性能

    在组中选择PID,Listagg(desc,'')作为描述
    从B组;

  2. 收集如果不需要排序(00:00:02.90):

    选择pid,to_string(cast(collect(desc)作为varchar2_ntt))作为b组的val;

  3. 用订购收集的vals vals b grout siter lit litlow show(00:00:07.088) ):

    选择pid,to_string(cast(cast(desc of desc)作为varchar2_ntt collect(DESC订单))作为b group by b groud pid;

所有其他技术都较慢。

  1. LISTAGG delivers the best performance if sorting is a must(00:00:05.85)

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

  2. COLLECT delivers the best performance if sorting is not needed(00:00:02.90):

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

  3. COLLECT with ordering is bit slower(00:00:07.08):

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

All other techniques were slower.

So尛奶瓶 2025-02-12 15:45:42

在运行选择查询之前,请运行以下操作:

在size 6000 上设置serverout

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

Before you run a select query, run this:

SET SERVEROUT ON SIZE 6000

SELECT XMLAGG(XMLELEMENT(E,SUPLR_SUPLR_ID||',')).EXTRACT('//text()') "SUPPLIER" 
FROM SUPPLIERS;
靖瑶 2025-02-12 15:45:42

尝试此代码:

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

Try this code:

 SELECT XMLAGG(XMLELEMENT(E,fieldname||',')).EXTRACT('//text()') "FieldNames"
    FROM FIELD_MASTER
    WHERE FIELD_ID > 10 AND FIELD_AREA != 'NEBRASKA';
躲猫猫 2025-02-12 15:45:42

在选择您想要的位置的位置,请调用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

函数标头语法可能是错误的,但是原理确实有效。

In the select where you want your concatenation, call a SQL function.

For example:

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

Then for the SQL function:

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

The Function Header syntax might be wrong, but the principle does work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文