简体   繁体   English

使用 Oracle SQL,如何在不使用 PIVOT、LISTAGG 或自定义构建函数的情况下将多行数据连接到一行?

[英]Using Oracle SQL, how can I concatenate data from multiple rows into one row without using PIVOT, LISTAGG or custom built functions?

I'm using Oracle SQL.我正在使用 Oracle SQL。 This is the table:这是表格:

doc-nr doc-nr code代码 text文本
0000010 0000010 155 155 Sample text from code 155代码 155 中的示例文本
0000010 0000010 455 455 Sample text1 from code 455代码 455 中的示例 text1
0000010 0000010 455 455 Sample text2 from code 455来自代码 455 的示例 text2
0000010 0000010 455 455 Sample text3 from code 455来自代码 455 的示例 text3

With this query:使用此查询:

SELECT t155.text as "155", t455.text as "455" 
FROM myTable t155
JOIN myTable t455 ON t155.doc-nr = t455.doc-nr
WHERE t155.code = '155'
AND t455.code = '455'

I get ugly result:我得到丑陋的结果:

155 155 455 455
Sample text from code 155代码 155 中的示例文本 Sample text1 from code 455代码 455 中的示例 text1
Sample text from code 155代码 155 中的示例文本 Sample text2 from code 455来自代码 455 的示例 text2
Sample text from code 155代码 155 中的示例文本 Sample text3 from code 455来自代码 455 的示例 text3

I want the output to be one row:我希望 output 是一行:

155 155 455 455 455 455 455 455
Sample text from code 155代码 155 中的示例文本 Sample text1 from code 455代码 455 中的示例 text1 Sample text2 from code 455来自代码 455 的示例 text2 Sample text3 from code 455来自代码 455 的示例 text3

Or:或者:

155 155 455 455
Sample text from code 155代码 155 中的示例文本 Sample text1 from code 455;来自代码 455 的示例 text1; Sample text2 from code 455;来自代码 455 的示例 text2; Sample text3 from code 455来自代码 455 的示例 text3

How can you do this with Oracle SQL without using PIVOT or LISTAGG or using custom built functions?在不使用 PIVOT 或 LISTAGG 或使用自定义构建函数的情况下,如何使用 Oracle SQL 做到这一点?

You can create such a function returning SYS_REFCURSOR in order to pivot your data dynamically您可以创建这样的 function 返回SYS_REFCURSOR以便动态地 pivot 您的数据

CREATE OR REPLACE FUNCTION Get_Pivoted_Cols RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_cols1     VARCHAR2(32767);
  v_cols2     VARCHAR2(32767);  
BEGIN
  SELECT LISTAGG( ''''||rn||''' AS "'||rn||'"' , ',' ) WITHIN GROUP ( ORDER BY text ),
         LISTAGG( 'MAX("'||rn||'") AS "'||rn||'"' , ',' ) WITHIN GROUP ( ORDER BY text )
    INTO v_cols1, v_cols2
    FROM 
    ( SELECT code||'_'||ROW_NUMBER() OVER (PARTITION BY doc_nr, code ORDER BY text) AS rn, t.*
        FROM tab t );

  v_sql :='SELECT '||v_cols2||
          '  FROM
             (
              SELECT code||''_''||ROW_NUMBER() OVER (PARTITION BY doc_nr, code ORDER BY text) AS rn, t.*
                FROM tab t 
             )
            PIVOT
            (
             MAX(text) FOR rn IN ( '|| v_cols1 ||' )
            )
            GROUP BY doc_nr';            

  OPEN v_recordset FOR v_sql;
  DBMS_OUTPUT.PUT_LINE(v_sql);
  RETURN v_recordset;
END;

which will generate this output as a SQL statement这将生成此 output 作为 SQL 语句

SELECT MAX("155_1") AS "155_1", 
       MAX("455_1") AS "455_1", 
       MAX("455_2") AS "455_2", 
       MAX("455_3") AS "455_3"
  FROM
  (
   SELECT code||'_'||ROW_NUMBER() OVER (PARTITION BY doc_nr, code ORDER BY text) AS rn, 
          t.*
     FROM tab t 
  )
  PIVOT
  (
   MAX(text) FOR rn IN ( '155_1' AS "155_1", '455_1' AS "455_1", '455_2' AS "455_2", 
                         '455_3' AS "455_3" )
  )
  GROUP BY doc_nr;

Demo 演示

and then run this code:然后运行此代码:

VAR rc REFCURSOR
EXEC :rc := Get_Pivoted_Cols;
PRINT rc

from SQL Developer's Command Line in order to see the result set.SQL 开发人员的命令行中查看结果集。

If the problem is the size, you can use XML aggregation:如果问题是大小,可以使用 XML 聚合:

select mt.doc_nr, mt.text as text_155,
  xmlquery('
    for $i in .
      return <e>{ fn:string-join($i/text, "; ") }</e>/text()'
    passing tmp.xml
    returning content
  ).getclobval() as text_455
from mytable mt
join (
  select doc_nr, xmlagg(xmlelement("text", text)) as xml
  from mytable
  where code = 455
  group by doc_nr
) tmp
on tmp.doc_nr = mt.doc_nr
where mt.code = 155
DOC_NR  | TEXT_155                  | TEXT_455                                                                          
:------ | :------------------------ | :---------------------------------------------------------------------------------
0000010 | Sample text from code 155 | Sample text1 from code 455; Sample text3 from code 455; Sample text2 from code 455

db<>fiddle including the intermediate steps. db<>fiddle包括中间步骤。

Using xml functions in a such way is not good for performance (when there is more data) but in this case it works fine:以这种方式使用 xml 函数对性能不利(当有更多数据时),但在这种情况下它可以正常工作:

SELECT t155.text  as "155",
       sys_xmlagg(xmlelement(col, t455.text || ',')).extract('/ROWSET/COL/text()')
                 .getclobval() as "455"
  FROM myTable t155
  JOIN myTable t455
    ON t155."doc-nr" = t455."doc-nr"
 WHERE t155.code = '155'
   AND t455.code = '455'
 GROUP BY t155.text

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM