Oracleの複数行の列値を連結するSQLクエリ


169

複数の行の列値を連結するSQLを構築することは可能でしょうか?

次に例を示します。

テーブルA

PID
あ
B
C

表B

PID SEQ説明

A 1を持っている
A 2いい
3日。
B 1よくできました。
C 1はい
C 2できる 
C 3する 
C 4この作品!

SQLの出力は-

PID説明
A良い一日を。
Bよくできました。
Cはい、この作業を行うことができます!

基本的に、出力テーブルのDesc列は、テーブルBのSEQ値を連結したものですか?

SQLに関するヘルプはありますか?


例を参照してください:halisway.blogspot.com/2006/08/…– Andomar '13
1

このソリューションをご覧ください。重宝します。
Jineesh Uvantavida 2017

回答:


237

使用しているバージョンに応じていくつかの方法があります。文字列の集約手法に関するOracleのドキュメントを参照してください。非常に一般的なものは使用することLISTAGGです:

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

次に参加しAて、pids必要なものを選びます。

注:箱から出しLISTAGGて、VARCHAR2列でのみ正しく動作します。


2
Oracle 10gでwm_concat()を使用すると、コンマで区切られたシーケンス番号の昇順でテキストが連結されます。降順で別の区切りを作成できますか?
jagamot 2011年

19

XMLAGG11.2より前のバージョンで機能する関数もあります。WM_CONCATドキュメント化されておらず、Oracleサポートされていないため、本番システムでは使用しないことをお勧めします。

XMLAGGあなたは、次の操作を行うことができます。

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

これは何ですか

  • テーブルのename列(コンマで連結)の値をemployee_namesxml要素(タグE付き)に配置します
  • このテキストを抽出します
  • xmlを集約する(それを連結する)
  • 結果の列を「結果」と呼びます

XMLAGGはOracle 12.2で動作します。さらに、XLMAGGでは、非常に長い文字列を連結することができます。これは、LISTAGGが最終的な長さのためにできない場合があります。
Marco、

13

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スレッドへのリンクをたどると、パフォーマンスの比較など、さらに多くのことがわかります。



8

ほとんどの回答が示唆するように、LISTAGGは明白なオプションです。ただし、1つの厄介な点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;

上記は出力を4000文字に制限しますが、ORA-01489エラーをスローしません 。

これらは、ON OVERFLOW節の追加オプションの一部です。

  • ON OVERFLOW TRUNCATE 'Contd..' :これは'Contd..'文字列の最後に表示されます(デフォルトは...
  • ON OVERFLOW TRUNCATE '' :これにより、終了文字列なしで4000文字が表示されます。
  • ON OVERFLOW TRUNCATE WITH COUNT:これは、終了文字の後の最後に文字の総数を表示します。例:-' ...(5512)'
  • ON OVERFLOW ERRORLISTAGGORA-01489エラーで失敗する ことが予想される場合(これはとにかくデフォルトです)。

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;

キーと値がすべて1つのテーブルに含まれている場合もあります。次のクエリは、テーブル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;

すべての値は、必要に応じて並べ替えることができます。個々の連結された記述はPARTITION BY句で並べ替えることができ、PIDのリストは最後のORDER BY句で並べ替えることができます。


あるいは、テーブル全体のすべての値を1つの行に連結したい場合があります。

ここでの重要なアイデアは、連結する説明のグループに人工的な値を使用することです。

次のクエリでは、定数文字列「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;

個々の連結した説明は、PARTITION BY句で並べ替えることができます。

このページの他のいくつかの回答でも、この非常に役立つ参照について言及しています:https : //oracle-base.com/articles/misc/string-aggregation-techniques


3
  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. 順序付きのCOLLECTは少し遅いです(00:00:07.08):

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

他のすべての手法はより低速でした。


1
答えを詳しく説明するのに役立ちます。
Jon Surrell、2015

ジョン、私は記事から繰り返すことを望んでいませんでしたが、簡単に言えば、これらは結果です:1. LISTAGGは、ソートが必須である場合に最高のパフォーマンスを提供します(00:00:05.85)必要(00:00:02.90):SELECT pid、TO_STRING(CAST(COLLECT(Desc)AS varchar2_ntt))AS Vals FROM B GROUP BY pid; 3.順序付きのCOLLECTの方が少し遅い(00:00:07.08):SELECT pid、TO_STRING(CAST(COLLECT(Desc ORDER BY Desc)AS varchar2_ntt))AS Vals FROM B GROUP BY pid; 他のすべての手法はより低速でした。
Misho

1
回答を編集して関連情報を含めることができます。
Jon Surrell、2015年

編集が遅すぎたので、もう一度追加しました。申し訳ありませんが、私はここに初めて来て、こつこつ始め始めました。
Misho

1

選択クエリを実行する前に、これを実行します。

SET SERVEROUT ON SIZE 6000

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

-1

このコードを試してください:

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

-3

連結する場所の選択で、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

関数ヘッダーの構文は間違っている可能性がありますが、原則は機能します。


これはOracleでは無効です
a_horse_with_no_name '11
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.