複数の行の列値を連結する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に関するヘルプはありますか?
複数の行の列値を連結する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に関するヘルプはありますか?
回答:
使用しているバージョンに応じていくつかの方法があります。文字列の集約手法に関する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付き)に配置します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スレッドへのリンクをたどると、パフォーマンスの比較など、さらに多くのことがわかります。
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;
すべての値は、必要に応じて並べ替えることができます。個々の連結された記述は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
並べ替えが必須の場合、LISTAGGは最高のパフォーマンスを提供します(00:00:05.85)
SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description
FROM B GROUP BY pid;
COLLECTは、ソートが必要ない場合に最高のパフォーマンスを発揮します(00:00:02.90):
SELECT pid, TO_STRING(CAST(COLLECT(Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;
順序付きの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;
他のすべての手法はより低速でした。
選択クエリを実行する前に、これを実行します。
SET SERVEROUT ON SIZE 6000
SELECT XMLAGG(XMLELEMENT(E,SUPLR_SUPLR_ID||',')).EXTRACT('//text()') "SUPPLIER"
FROM SUPPLIERS;
このコードを試してください:
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
関数ヘッダーの構文は間違っている可能性がありますが、原則は機能します。