サブクエリ内の複数の結果を1つのコンマ区切り値に結合します


84

私は2つのテーブルを持っています:

TableA
------
ID,
Name

TableB
------
ID,
SomeColumn,
TableA_ID (FK for TableA)

関係は1行ですTableA-多くのTableB

今、私はこのような結果を見たいと思います:

ID     Name      SomeColumn

1.     ABC       X, Y, Z (these are three different rows)
2.     MNO       R, S

これは機能しません(サブクエリに複数の結果があります):

SELECT ID,
       Name, 
       (SELECT SomeColumn FROM TableB WHERE F_ID=TableA.ID)
FROM TableA

クライアント側で処理を行う場合、これは些細な問題です。ただし、これは、すべてのページでXクエリを実行する必要があることを意味します。Xはの結果の数ですTableA

の行に対して複数の結果が返されるため、GROUPBYなどを単純に実行することはできないことに注意してくださいTableA

COALESCEなどを利用したUDFが機能するかどうかわかりませんか?

回答:


134

これでも目的を果たします

サンプルデータ

declare @t table(id int, name varchar(20),somecolumn varchar(MAX))
insert into @t
    select 1,'ABC','X' union all
    select 1,'ABC','Y' union all
    select 1,'ABC','Z' union all
    select 2,'MNO','R' union all
    select 2,'MNO','S'

クエリ:

SELECT ID,Name,
    STUFF((SELECT ',' + CAST(T2.SomeColumn AS VARCHAR(MAX))
     FROM @T T2 WHERE T1.id = T2.id AND T1.name = T2.name
     FOR XML PATH('')),1,1,'') SOMECOLUMN
FROM @T T1
GROUP BY id,Name

出力:

ID  Name    SomeColumn
1   ABC     X,Y,Z
2   MNO     R,S

13
ユーザー機能を必要とせずに問題を解決するので、なぜこれが取り上げられなかったのかわかりません。ここで表現されているのと同じアイデアを見ることができますcodecorner.galanter.net/2009/06/25/…これはこの回答よりも前のものであり、「オリジナル」である可能性があります
Paul D'Ambra

1
ここでも同じですが、なぜこれが高く評価されないのかわかりません
Marcel

1
こんにちはpriyanka、ここで「and t1.name = t2.name」句が必要かどうか、またその理由を教えてください。
Koen

2
これは素晴らしいです。私はサーバーを殺していた受け入れられた答えにリストされているようにUDF関数を最適化しようとしていました。102秒の検索から1未満になりました。実行プランの比較は78%〜22%でしたが、実行時間とは関係ありません...
toxaq 2011

その先頭の「」が必要になることを思い出してください。そうしないと、出力に山かっこが含まれることになります。
ティム・スカボロー2012年

45

1.UDFを作成します。

CREATE FUNCTION CombineValues
(
    @FK_ID INT -- The foreign key from TableA which is used 
               -- to fetch corresponding records
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @SomeColumnList VARCHAR(8000);

SELECT @SomeColumnList =
    COALESCE(@SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20)) 
FROM TableB C
WHERE C.FK_ID = @FK_ID;

RETURN 
(
    SELECT @SomeColumnList
)
END

2.サブクエリで使用します。

SELECT ID, Name, dbo.CombineValues(FK_ID) FROM TableA

3.ストアドプロシージャを使用している場合は、次のように実行できます。

CREATE PROCEDURE GetCombinedValues
 @FK_ID int
As
BEGIN
DECLARE @SomeColumnList VARCHAR(800)
SELECT @SomeColumnList =
    COALESCE(@SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20)) 
FROM TableB
WHERE FK_ID = @FK_ID 

Select *, @SomeColumnList as SelectedIds
    FROM 
        TableA
    WHERE 
        FK_ID = @FK_ID 
END

1
これはまだハックのように感じます。私はまだサブクエリを使用しているので、まだ多くの追加処理が行われています。より良い解決策が存在すると確信しています(テーブルの再構築、または問題を調べる別の方法)。
ドニートーマス

1
私はこれをハックとは呼びません。カーソルよりも効率的であり、データを希望どおりに構造化して一時テーブルを作成するために必要なオーバーヘッドがありません。
スコットローレンス

1
列をパラメータにすることはできません。現状では、すべての子の関係のための関数を作成する必要があります!
ジョンポールジョーンズ

1
それは大丈夫です-私はこれらの特定の列だけを組み合わせる必要があります。残りは「従来の」結合です。
ドニートーマス

この方法なしでこれを行う最良の方法を思い出せません。
AF。

11

あなたはCOALESCEで正しい方向に進んでいると思います。カンマ区切りの文字列を作成する例については、次を参照してください。

http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string


2
驚くばかり!COALESCEについて説明しているリンクを見たことがありますが、それらにはトリガー付きのUDFの作成が含まれていました。送信したリンクには、単一のSELECTステートメントを含むキーがあります。他の人が見つけやすいように、正しい解決策で答えを追加しています。ありがとう!
ドニートーマス

1
こんにちはベン、答えにはもう少し詳細が必要だと思います。つまり、UDFの作成方法などです。これがわかったら、コミュニティで編集可能な答えとしてソリューションを追加します。お気軽に編集してください。それ以降は回答として承ります。混乱させて申し訳ありません。
ドニートーマス

11

MySQLには、要求しているものを返すgroup_concat関数があります。

SELECT TableA.ID, TableA.Name, group_concat(TableB.SomeColumn) 
as SomColumnGroup FROM TableA LEFT JOIN TableB ON 
TableB.TableA_ID = TableA.ID

1
SQL Serverに同様の機能があれば、これは完璧だったでしょう。現状では、私はベンのソリューションを使用して、必要なものをまとめています。
ドニートーマス

0

より正確な応答を得るには、さらに詳細を提供する必要がある場合があります。

データセットはやや狭いように思われるため、結果ごとに1行を使用し、クライアントで後処理を実行することを検討してください。

したがって、サーバーに作業を行わせることを本当に検討している場合は、次のような結果セットが返されます。

ID       Name       SomeColumn
1        ABC        X
1        ABC        Y
1        ABC        Z
2        MNO        R
2        MNO        S

もちろん、これはIDの単純な内部結合です。

結果セットをクライアントに戻したら、CurrentNameという変数を維持し、それをトリガーとして使用して、SomeColumnを目的の便利なものに収集するのをやめます。


私はこれを考えましたが、これが洗練されたソリューションであるかどうかはよくわかりませんでした。SQLServerに、さらに処理する必要のない、適切に構築された結果セットを返してもらいたいのです。追加の詳細が必要ですか?テーブル構造を単純化しましたが、あなたはそれを持っていると思います。
ドニートーマス

0

テーブルAにWHERE句しかない場合は、次のようにストアドプロシージャを作成します。

SELECT Id, Name From tableA WHERE ...

SELECT tableA.Id AS ParentId, Somecolumn 
FROM tableA INNER JOIN tableB on TableA.Id = TableB.F_Id 
WHERE ...

次に、DataSetdsにそれを入力します。次に

ds.Relations.Add("foo", ds.Tables[0].Columns("Id"), ds.Tables[1].Columns("ParentId"));

最後に、すべての行にコンマを配置するリピーターをページに追加できます

 <asp:DataList ID="Subcategories" DataKeyField="ParentCatId" 
DataSource='<%# Container.DataItem.CreateChildView("foo") %>' RepeatColumns="1"
 RepeatDirection="Horizontal" ItemStyle-HorizontalAlign="left" ItemStyle-VerticalAlign="top" 
runat="server" >

このようにして、クライアント側で実行しますが、クエリは1つだけで、データベースとフロントエンド間で最小限のデータを渡します。


0

priyanka.sarkarが言及した解決策を試しましたが、OPの要求どおりに機能しませんでした。これが私が最終的に得た解決策です:

SELECT ID, 
        SUBSTRING((
            SELECT ',' + T2.SomeColumn
            FROM  @T T2 
            WHERE WHERE T1.id = T2.id
            FOR XML PATH('')), 2, 1000000)
    FROM @T T1
GROUP BY ID

-1

以下の解決策:

SELECT GROUP_CONCAT(field_attr_best_weekday_value)as RAVI
FROM content_field_attr_best_weekday LEFT JOIN content_type_attraction
    on content_field_attr_best_weekday.nid = content_type_attraction.nid
GROUP BY content_field_attr_best_weekday.nid

これを使用して、結合を変更することもできます


-1
SELECT t.ID, 
       t.NAME, 
       (SELECT t1.SOMECOLUMN 
        FROM   TABLEB t1 
        WHERE  t1.F_ID = T.TABLEA.ID) 
FROM   TABLEA t; 

これは、サブクエリを使用して別のテーブルから選択する場合に機能します。


-1

私はすべての答えを確認しました。データベースへの挿入は次のようになります。

ID     Name      SomeColumn
1.     ABC       ,X,Y Z (these are three different rows)
2.     MNO       ,R,S

カンマは前の端にある必要があり、次のように検索します %,X,%

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