Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Un moyen simple de transposer des colonnes et des lignes en SQL ?

Il existe plusieurs façons de transformer ces données. Dans votre message d'origine, vous avez déclaré que PIVOT semble trop complexe pour ce scénario, mais il peut être appliqué très facilement en utilisant à la fois le UNPIVOT et PIVOT fonctions dans SQL Server.

Cependant, si vous n'avez pas accès à ces fonctions, cela peut être répliqué en utilisant UNION ALL à UNPIVOT puis une fonction d'agrégation avec un CASE déclaration à PIVOT :

Créer un tableau :

CREATE TABLE yourTable([color] varchar(5), [Paul] int, [John] int, [Tim] int, [Eric] int);

INSERT INTO yourTable
    ([color], [Paul], [John], [Tim], [Eric])
VALUES
    ('Red', 1, 5, 1, 3),
    ('Green', 8, 4, 3, 5),
    ('Blue', 2, 2, 9, 1);

Union All, Version Agrégée et CASE :

select name,
  sum(case when color = 'Red' then value else 0 end) Red,
  sum(case when color = 'Green' then value else 0 end) Green,
  sum(case when color = 'Blue' then value else 0 end) Blue
from
(
  select color, Paul value, 'Paul' name
  from yourTable
  union all
  select color, John value, 'John' name
  from yourTable
  union all
  select color, Tim value, 'Tim' name
  from yourTable
  union all
  select color, Eric value, 'Eric' name
  from yourTable
) src
group by name

Voir SQL Fiddle avec démo

L'UNION ALL effectue l'UNPIVOT des données en transformant les colonnes Paul, John, Tim, Eric en rangées séparées. Ensuite, vous appliquez la fonction d'agrégation sum() avec le case déclaration pour obtenir les nouvelles colonnes pour chaque color .

Version non pivotée et pivotement statique :

L'UNPIVOT et PIVOT Les fonctions du serveur SQL rendent cette transformation beaucoup plus facile. Si vous connaissez toutes les valeurs que vous souhaitez transformer, vous pouvez les coder en dur dans une version statique pour obtenir le résultat :

select name, [Red], [Green], [Blue]
from
(
  select color, name, value
  from yourtable
  unpivot
  (
    value for name in (Paul, John, Tim, Eric)
  ) unpiv
) src
pivot
(
  sum(value)
  for color in ([Red], [Green], [Blue])
) piv

Voir SQL Fiddle avec démo

La requête interne avec le UNPIVOT remplit la même fonction que UNION ALL . Il prend la liste des colonnes et la transforme en lignes, le PIVOT effectue ensuite la transformation finale en colonnes.

Version pivot dynamique :

Si vous avez un nombre inconnu de colonnes (Paul, John, Tim, Eric dans votre exemple) puis un nombre inconnu de couleurs à transformer, vous pouvez utiliser sql dynamique pour générer la liste à UNPIVOT puis PIVOT :

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('yourtable') and
               C.name <> 'color'
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(color)
                    from yourtable t
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query 
  = 'select name, '[email protected]+'
      from
      (
        select color, name, value
        from yourtable
        unpivot
        (
          value for name in ('[email protected]+')
        ) unpiv
      ) src
      pivot
      (
        sum(value)
        for color in ('[email protected]+')
      ) piv'

exec(@query)

Voir SQL Fiddle avec démo

La version dynamique interroge à la fois yourtable puis le sys.columns table pour générer la liste des éléments à UNPIVOT et PIVOT . Ceci est ensuite ajouté à une chaîne de requête à exécuter. Le plus de la version dynamique est si vous avez une liste changeante de colors et/ou names cela générera la liste au moment de l'exécution.

Les trois requêtes produiront le même résultat :

| NAME | RED | GREEN | BLUE |
-----------------------------
| Eric |   3 |     5 |    1 |
| John |   5 |     4 |    2 |
| Paul |   1 |     8 |    2 |
|  Tim |   1 |     3 |    9 |