web-dev-qa-db-ja.com

1対多のフィールドを単一の結果に連結しますか?

次のクエリがあるとします。

SELECT * 
FROM AppDetails, AppTags 
WHERE AppDetails.AppID = '1' 
  AND AppDetails.AppID = AppTags.AppID

次の結果が得られます。

AppID    AppName        AppType    Tag
1        Application1   Utility    Test1
1        Application1   Utility    Test2
1        Application1   Utility    Test3

次のようなものを返すようにクエリを変更するにはどうすればよいですか。

AppID    AppName        AppType    Tags
1        Application1   Utility    Test1,Test2,Test3
7

残念ながら、SQL Serverにはグループ連結を実行する単一の関数はありませんが、結果を得るにはいくつかの方法があります。

_FOR XML PATH_ および STUFF() を実装できます。

_SELECT DISTINCT d.AppId,
  d.AppName,
  d.AppType,
  Tags = STUFF((SELECT ', ' + t.TagName
                FROM AppTags t
                where d.AppID = t.AppID
                FOR XML PATH (''))
                , 1, 1, '') 
FROM AppDetails d
WHERE d.AppID = '1';
_

SQL Fiddle with Demo を参照してください。

または、_FOR XML PATH_と_CROSS APPLY_を併用することもできます。

_SELECT DISTINCT d.AppId,
  d.AppName,
  d.AppType,
  tags = left(t.tags, len(t.tags)-1) 
FROM AppDetails d
CROSS APPLY
(
  SELECT t.TagName + ', '
  FROM AppTags t
  WHERE d.AppID = t.AppID
  FOR XML PATH('')
) t (Tags)
WHERE d.AppID = '1';
_

SQL Fiddle with Demo を参照してください。

次にtags値に対してクエリを実行する場合は、次のようなCTEを使用できます。

_;with cte as
(
  SELECT DISTINCT d.AppId,
    d.AppName,
    d.AppType,
    Tags = STUFF((SELECT ', ' + t.TagName
                  FROM AppTags t
                  where d.AppID = t.AppID
                  FOR XML PATH (''))
                  , 1, 1, '') 
  FROM AppDetails d
  WHERE d.AppID = '1'
)
select *
from cte
where tags like '%test1%'
_

参照 デモ

TagNameに特定のXML文字(例:_>_、_&_)が含まれている場合、これらは文字化されます(_>_-> _>_、_&_-> _&_)。これを回避するには、FOR XML PATH('')FOR XML PATH, TYPE).value(N'.[1]',N'nvarchar(max)')に変更します。

10
Taryn