Sql PIVOT和字符串连接聚合

时间:2013-02-09 00:47:18

标签: sql tsql pivot reporting-services reportbuilder3.0

我想使用pivot SQL查询来构造一个结果表,其中连接文本作为数据透视表的DATA部分中的结果。

即。我使用简单的选择得到以下结果:

+------------+-----------------+---------------+
| Event Name | Resource Type   | Resource Name |
+------------+-----------------+---------------+
| 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   |
+------------+-----------------+---------------+

我想构建一个如下所示的结果查询:

+---------------------+------------------------+------------------------+---------------------------------------+-----------------+-------------------------------------+
| Event/Resource Type | 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 |
+---------------------+------------------------+------------------------+---------------------------------------+-----------------+-------------------------------------+

我知道如何在ms-sql中使用PIVOT语句,但我不知道如何将资源名称聚合为每种资源类型的逗号分隔项的串联。

P.S 我还可以使用SSRS 2008-R2提供的Martix解决方案,使用Report Builde 3,第一个表作为我的数据集,并创建一个矩阵,将资源名称聚合成逗号分隔的字符串。

4 个答案:

答案 0 :(得分:16)

为了获得结果,首先应将值连接到逗号分隔列表中。

我会使用CROSS APPLYFOR 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 |

答案 1 :(得分:4)

这在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; 

答案 2 :(得分:2)

在报告构建器中,您应使用矩阵向导,然后执行以下操作:

  • Resource Type字段作为列组。
  • Event Name字段作为行组。
  • Resource Name字段作为详细信息,必须使用聚合函数,例如Count

在此阶段完成向导,然后完成编辑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

答案 3 :(得分:0)

完整的工作示例:

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