web-dev-qa-db-fra.com

Sql PIVOT et agrégat de concaténation de chaînes

J'aimerais utiliser une requête SQL pivot pour construire une table de résultats dans laquelle le texte concaténé résulte en tant que résultat dans la section DATA du tableau croisé dynamique.

c’est-à-dire que j’ai le résultat suivant en utilisant une sélection simple:

 + ------------ + ----------------- + ------------- - + 
 | Nom de l'événement | Type de ressource | Nom de la ressource | 
 + ------------ + ----------------- + ---------- ----- + 
 | Événement 1 | Type de ressource 1 | Ressource 1 | 
 | Événement 1 | Type de ressource 1 | Ressource 2 | 
 | Événement 1 | Type de ressource 2 | Ressource 3 | 
 | Événement 1 | Type de ressource 2 | Ressource 4 | 
 | Événement 1 | Type de ressource 3 | Ressource 5 | 
 | Événement 1 | Type de ressource 3 | Ressource 6 | 
 | Événement 1 | Type de ressource 3 | Ressource 7 | 
 | Événement 1 | Type de ressource 4 | Ressource 8 | 
 | Événement 2 | Type de ressource 5 | Ressource 1 | 
 | Événement 2 | Type de ressource 2 | Ressource 3 | 
 | Événement 2 | Type de ressource 3 | Ressource 11 | 
 | Événement 2 | Type de ressource 3 | Ressource 12 | 
 | Événement 2 | Type de ressource 3 | Ressource 13 | 
 | Événement 2 | Type de ressource 4 | Ressource 14 | 
 | Événement 2 | Type de ressource 5 | Ressource 9 | 
 | Événement 2 | Type de ressource 5 | Ressource 16 | 
 + ------------ + ----------------- + ---------- ----- + 

Et je voudrais construire une requête de résultat qui ressemblerait à ceci:

 + --------------------- + ---------------------- - + ------------------------ + ---------------------- ----------------- + ----------------- + -------------- ----------------------- + 
 | Type d'événement/ressource | Type de ressource 1 | Type de ressource 2 | Type de ressource 3 | Type de ressource 4 | Type de ressource 5 | 
 + --------------------- + ------------------ ------ + ------------------------ + ------------------ --------------------- + ----------------- + ---------- --------------------------- + 
 | Événement 1 | Ressource 1, Ressource 2 | Ressource 3, ressource 4 | Ressource 5, Ressource 6, Ressource 7 | Ressource 8 | NUL                                 | 
 | Événement 2 | NUL                    | Ressource 3 | Ressource 11, Ressource 12, Ressource 13 | Ressource 14 | Ressource 1, Ressource 9, Ressource 16 | 
 + --------------------- + ------------- ----------- + ------------------------ + ------------- -------------------------- + ----------------- + ----- -------------------------------- + 

Je sais comment utiliser une instruction PIVOT dans ms-sql mais je ne sais pas comment agréger le nom de la ressource en une concaténation d'éléments séparés par des virgules pour chaque type de ressource.

P.S Je pourrais également utiliser une solution utilisant Martix fournie par SSRS 2008-R2 en utilisant Report Builde 3 avec la première table en tant que jeu de données et créer une matrice qui agrégera les noms de ressources dans une chaîne séparée par des virgules.

18
Mortalus

Pour obtenir le résultat, vous devez d'abord concaténer les valeurs dans la liste séparée par des virgules. 

J'utiliserais CROSS APPLY et 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)

Voir SQL Fiddle avec Demo . Le résultat vous donne:

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

Ensuite, vous appliquerez votre PIVOT à ce résultat:

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

Voir SQL Fiddle avec Demo . Votre résultat final sera alors:

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

Cela fonctionne pour moi dans SQL 2008 et est dynamique - gérera un Resource Type supplémentaire

SQLFiddle de travail

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

Dans le générateur de rapport, vous devez utiliser le Table ou Matrix wizard et procéder comme suit:

  • Resource Type champ en tant que groupes de colonnes.
  • Event Name champ en tant que groupes de lignes.
  • Et dans le champ Resource Name, vous devrez utiliser une fonction de regroupement telle que Count.

À ce stade, terminez l’assistant, puis une fois terminé, éditez la cellule Resource Name en tant qu’expression. Remplacez l'expression par:

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

Maintenant essayé et testé:

enter image description here

2
glh

Exemple de travail complet:

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