質問

複数の行から列値を連結するために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からの配列値の連結ですか?

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文書化されておらず、オラクルによってサポートされていません, 、生産システムで使用しないことをお勧めします。

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/stringaggregationtechniques.php

文字列連結

ほとんどの答えが示唆するように、 LISTAGG 明らかなオプションです。ただし、1つの迷惑な側面 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(または以前)を使用してこの問題を解決しなければならない場合は、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;

すべての値は、必要に応じて並べ替えることができます。個々の連結説明は、句ごとにパーティションで並べ替えることができ、PIDのリストは句ごとに最終順序で並べ替えることができます。


代わりに: テーブル全体からすべての値を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;

個々の連結説明は、句ごとにパーティションで並べ替えることができます。

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

  1. ListAggは、ソートが必須である場合に最高のパフォーマンスを提供します(00:00:05.85)

    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