sql >> Base de Datos >  >> RDS >> Sqlserver

¿Manera simple de transponer columnas y filas en SQL?

Hay varias formas de transformar estos datos. En su publicación original, indicó que PIVOT parece demasiado complejo para este escenario, pero se puede aplicar muy fácilmente usando tanto el UNPIVOT y PIVOT funciones en SQL Server.

Sin embargo, si no tiene acceso a esas funciones, esto se puede replicar usando UNION ALL a UNPIVOT y luego una función agregada con un CASE declaración a PIVOT :

Crear tabla:

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

Unir todo, agregado y versión 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

Ver SQL Fiddle con demostración

El UNION ALL realiza el UNPIVOT de los datos transformando las columnas Paul, John, Tim, Eric en filas separadas. Luego aplica la función agregada sum() con el case declaración para obtener las nuevas columnas para cada color .

Versión estática sin pivotar y pivote:

Tanto el UNPIVOT y PIVOT Las funciones en el servidor SQL hacen que esta transformación sea mucho más fácil. Si conoce todos los valores que desea transformar, puede codificarlos en una versión estática para obtener el resultado:

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

Ver SQL Fiddle con demostración

La consulta interna con UNPIVOT realiza la misma función que UNION ALL . Toma la lista de columnas y la convierte en filas, el PIVOT luego realiza la transformación final en columnas.

Versión dinámica dinámica:

Si tiene un número desconocido de columnas (Paul, John, Tim, Eric en su ejemplo) y luego un número desconocido de colores para transformar, puede usar sql dinámico para generar la lista para UNPIVOT y luego 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)

Ver SQL Fiddle con demostración

La versión dinámica consulta tanto yourtable y luego sys.columns tabla para generar la lista de elementos a UNPIVOT y PIVOT . Esto luego se agrega a una cadena de consulta para ser ejecutado. La ventaja de la versión dinámica es si tiene una lista cambiante de colors y/o names esto generará la lista en tiempo de ejecución.

Las tres consultas producirán el mismo resultado:

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