web-dev-qa-db-ja.com

SQL PIVOTと文字列連結集計

ピボットSQLクエリを使用して、結果としてピボットテーブルのDATAセクション内に連結テキストを結果として含む結果テーブルを構築したいと思います。

つまり、単純な選択を使用した結果、次のようになります。

 + ------------ + ----------------- + ------------- -+ 
 |イベント名|リソースの種類|リソース名| 
 + ------------ + ----------------- + ---------- ----- + 
 |イベント1 |リソースタイプ1 |リソース1 | 
 |イベント1 |リソースタイプ1 |リソース2 | 
 |イベント1 |リソースタイプ2 |リソース3 | 
 |イベント1 |リソースタイプ2 |リソース4 | 
 |イベント1 |リソースタイプ3 |リソース5 | 
 |イベント1 |リソースタイプ3 |リソース6 | 
 |イベント1 |リソースタイプ3 |リソース7 | 
 |イベント1 |リソースタイプ4 |リソース8 | 
 |イベント2 |リソースタイプ5 |リソース1 | 
 |イベント2 |リソースタイプ2 |リソース3 | 
 |イベント2 |リソースタイプ3 |リソース11 | 
 |イベント2 |リソースタイプ3 |リソース12 | 
 |イベント2 |リソースタイプ3 |リソース13 | 
 |イベント2 |リソースタイプ4 |リソース14 | 
 |イベント2 |リソースタイプ5 |リソース9 | 
 |イベント2 |リソースタイプ5 |リソース16 | 
 + ------------ + ----------------- + ---------- ----- + 

そして、次のような結果クエリを作成したいと思います。

 + --------------------- + ---------------------- -+ ------------------------ + ---------------------- ----------------- + ----------------- + -------------- ----------------------- + 
 |イベント/リソースタイプ|リソースタイプ1 |リソースタイプ2 |リソースタイプ3 |リソースタイプ4 |リソースタイプ5 | 
 + --------------------- + ------------------ ------ + ------------------------ + ------------------ --------------------- + ----------------- + ---------- --------------------------- + 
 |イベント1 |リソース1、リソース2 |リソース3、リソース4 |リソース5、リソース6、リソース7 |リソース8 | ヌル                                | 
 |イベント2 | ヌル                   |リソース3 |リソース11、リソース12、リソース13 |リソース14 |リソース1、リソース9、リソース16 | 
 + --------------------- + ------------- ----------- + ------------------------ + ------------- -------------------------- + ----------------- + ----- -------------------------------- + 

Ms-sqlでPIVOTステートメントを使用する方法は知っていますが、リソース名を各リソースタイプのコンマ区切り項目の連結に集約する方法がわかりません。

P.Sまた、最初のテーブルをデータセットとしてReport Builde 3を使用し、SSRS 2008-R2が提供するMartixを使用するソリューションを使用して、リソース名をカンマ区切りの文字列に集約するマトリックスを作成することもできます。

21
Mortalus

結果を取得するには、まず値をコンマ区切りのリストに連結する必要があります。

私は使うだろう CROSS APPLYおよびFOR XML PATH

SELECT distinct e.[Event Name],
  e.[Resource Type],
  LEFT(r.ResourceName , LEN(r.ResourceName)-1) ResourceName
FROM yourtable e
CROSS APPLY
(
    SELECT r.[Resource Name] + ', '
    FROM yourtable r
    where e.[Event Name] = r.[Event Name]
      and e.[Resource Type] = r.[Resource Type]
    FOR XML PATH('')
) r (ResourceName)

SQL Fiddle with Demo を参照してください。結果は次のようになります。

| EVENT NAME |   RESOURCE TYPE |                          RESOURCENAME |
------------------------------------------------------------------------
|    Event 1 | Resource Type 1 |                Resource 1, Resource 2 |
|    Event 1 | Resource Type 2 |                Resource 3, Resource 4 |
|    Event 1 | Resource Type 3 |    Resource 5, Resource 6, Resource 7 |
|    Event 1 | Resource Type 4 |                            Resource 8 |
|    Event 2 | Resource Type 2 |                            Resource 3 |
|    Event 2 | Resource Type 3 | Resource 11, Resource 12, Resource 13 |
|    Event 2 | Resource Type 4 |                           Resource 14 |
|    Event 2 | Resource Type 5 |   Resource 1, Resource 9, Resource 16 |

次に、PIVOTをこの結果に適用します。

SELECT [Event Name],
  [Resource Type 1], [Resource Type 2],
  [Resource Type 3], [Resource Type 4],
  [Resource Type 5]
FROM
(
  SELECT distinct e.[Event Name],
    e.[Resource Type],
    LEFT(r.ResourceName , LEN(r.ResourceName)-1) ResourceName
  FROM yourtable e
  CROSS APPLY
  (
      SELECT r.[Resource Name] + ', '
      FROM yourtable r
      where e.[Event Name] = r.[Event Name]
        and e.[Resource Type] = r.[Resource Type]
      FOR XML PATH('')
  ) r (ResourceName)
) src
pivot
(
  max(ResourceName)
  for [Resource Type] in ([Resource Type 1], [Resource Type 2],
                          [Resource Type 3], [Resource Type 4],
                          [Resource Type 5])
) piv

SQL Fiddle with Demo を参照してください。最終的な結果は次のようになります。

| EVENT NAME |        RESOURCE TYPE 1 |        RESOURCE TYPE 2 |                       RESOURCE TYPE 3 | RESOURCE TYPE 4 |                     RESOURCE TYPE 5 |
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|    Event 1 | Resource 1, Resource 2 | Resource 3, Resource 4 |    Resource 5, Resource 6, Resource 7 |      Resource 8 |                              (null) |
|    Event 2 |                 (null) |             Resource 3 | Resource 11, Resource 12, Resource 13 |     Resource 14 | Resource 1, Resource 9, Resource 16 |
19
Taryn

これはSQL 2008で私にとっては機能し、動的です-追加のResource Typeを処理します

Working SQLFiddle

IF OBJECT_ID('tempdb..#test') IS NOT NULL
  DROP TABLE #test

GO

CREATE TABLE #test
  (
     eventName    VARCHAR(30),
     resourceType VARCHAR(30),
     resourceName VARCHAR(30)
  );

INSERT INTO #test
VALUES      ('Event 1','Resource Type 1','Resource 1'),
            ('Event 1','Resource Type 1','Resource 2'),
            ('Event 1','Resource Type 2','Resource 3'),
            ('Event 1','Resource Type 2','Resource 4'),
            ('Event 1','Resource Type 3','Resource 5'),
            ('Event 1','Resource Type 3','Resource 6'),
            ('Event 1','Resource Type 3','Resource 7'),
            ('Event 1','Resource Type 4','Resource 8'),
            ('Event 2','Resource Type 5','Resource 1'),
            ('Event 2','Resource Type 2','Resource 3'),
            ('Event 2','Resource Type 3','Resource 11'),
            ('Event 2','Resource Type 3','Resource 12'),
            ('Event 2','Resource Type 3','Resource 13'),
            ('Event 2','Resource Type 4','Resource 14'),
            ('Event 2','Resource Type 5','Resource 9'),
            ('Event 2','Resource Type 5','Resource 16');

DECLARE @resourceTypes VARCHAR(max);

SELECT @resourceTypes = stuff((SELECT DISTINCT ',[' + resourceType + ']'
                               FROM   #test
                               FOR xml path('')), 1, 1, '');
DECLARE @query NVARCHAR(max);

SET @query = 'SELECT *
FROM   (SELECT eventName,
               resourceType,
               stuff((SELECT '','' + resourceName + ''''
                      FROM   #test b
                      WHERE  a.eventName = b.eventName
                             AND a.resourceType = b.resourceType
                      FOR xml path('''')), 1, 1, '''') resourceName
        FROM   #test a
        GROUP  BY eventName,
                  resourceType) AS data PIVOT (max(resourceName) FOR resourceType IN (' + @resourceTypes + ')) AS pvt';

EXEC(@query);

DROP TABLE #test; 
4
Paul

レポートビルダーでは、TableまたはMatrixウィザードを使用して、以下を実行する必要があります。

  • 列グループとしてのResource Typeフィールド。
  • 行グループとしてのEvent Nameフィールド。
  • そしてResource Nameフィールドの詳細として、あなたはwillCountなどの集計関数を使用する必要があります。

この段階でウィザードを完了し、完了したらResource Nameセルを式として編集します。式を次で置き換えます。

=Join( LookupSet( Fields!EVENT_NAME.Value + Fields!RESOURCE_TYPE.Value,
                  Fields!EVENT_NAME.Value + Fields!RESOURCE_TYPE.Value,
                  Fields!RESOURCE_NAME.Value, "DataSet1"), ", ")

試してテストしました:

enter image description here

2
glh

完全に機能する例:

SET NOCOUNT ON
GO

    DECLARE @SourceTable TABLE
    (
         EventName NVARCHAR(10)
        ,ResourceType NVARCHAR(20)
        ,ResourceName NVARCHAR(20)
    )

    INSERT INTO @SourceTable(EventName,ResourceType,ResourceName)
    VALUES   ('Event 1','Resource Type 1','Resource 1')
            ,('Event 1','Resource Type 1','Resource 2') 
            ,('Event 1','Resource Type 2','Resource 3') 
            ,('Event 1','Resource Type 2','Resource 4')
            ,('Event 1','Resource Type 3','Resource 5') 
            ,('Event 1','Resource Type 3','Resource 6') 
            ,('Event 1','Resource Type 3','Resource 7') 
            ,('Event 1','Resource Type 4','Resource 8') 
            ,('Event 2','Resource Type 5','Resource 1') 
            ,('Event 2','Resource Type 2','Resource 3') 
            ,('Event 2','Resource Type 3','Resource 11')
            ,('Event 2','Resource Type 3','Resource 12')
            ,('Event 2','Resource Type 3','Resource 13')
            ,('Event 2','Resource Type 4','Resource 14')
            ,('Event 2','Resource Type 5','Resource 9') 
            ,('Event 2','Resource Type 5','Resource 16') 

    ;WITH SourceTable AS
    (
        SELECT DISTINCT ST1.EventName
                       ,ST1.ResourceType
                       ,(SELECT SUBSTRING((SELECT ',' +ResourceName 
                                           FROM @SourceTable AS ST2
                                           WHERE ST1.EventName=ST2.EventName AND ST1.ResourceType=ST2.ResourceType 
                                           FOR XML PATH('')),2,200) AS CSV) AS ResourceName
        FROM @SourceTable AS ST1
    )
    SELECT    EventName
            ,[Resource Type 1]
            ,[Resource Type 2]
            ,[Resource Type 3]
            ,[Resource Type 4]
            ,[Resource Type 5]
    FROM 
    (
        SELECT EventName
              ,ResourceType
              ,ResourceName
        FROM SourceTable
    ) PivotSource
    PIVOT
    (
        MAX(ResourceName) FOR ResourceType  IN ([Resource Type 1],[Resource Type 2],[Resource Type 3],[Resource Type 4],[Resource Type 5])
    ) PivotTable

SET NOCOUNT OFF
GO
0
gotqn