Sql PIVOT and string concatenation aggregate

前端 未结 4 1751
梦谈多话
梦谈多话 2020-11-27 19:45

I would like to use a pivot SQL query to construct a result table where the concatenate text as a result within the DATA section of the pivot table.

i.e. i have the

相关标签:
4条回答
  • 2020-11-27 20:06

    In order to get the result, first you should concatenate the values into the comma separated list.

    I would use CROSS APPLY and 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)
    

    See SQL Fiddle with Demo. The gives you result:

    | 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 |
    

    Then you will apply your PIVOT to this result:

    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
    

    See SQL Fiddle with Demo. Your final result will then be:

    | 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 |
    
    0 讨论(0)
  • 2020-11-27 20:08

    Full working example:

    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 讨论(0)
  • 2020-11-27 20:09

    In report builder you should use the Table or Matrix wizard and do the following:

    • Resource Type field as the column groups.
    • Event Name field as the row groups.
    • And Resource Name field as details, you will have to use an aggregatre function such as Count.

    At this stage complete the wizard then once complete edit the Resource Name cell as an expression. Replace the expression with:

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

    Now tried and tested:

    enter image description here

    0 讨论(0)
  • 2020-11-27 20:13

    This works for me in SQL 2008, and it's dynamic - will handle additional 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; 
    
    0 讨论(0)
提交回复
热议问题