Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Einfache Möglichkeit, Spalten und Zeilen in SQL zu transponieren?

Es gibt mehrere Möglichkeiten, diese Daten umzuwandeln. In Ihrem ursprünglichen Beitrag haben Sie angegeben, dass PIVOT erscheint für dieses Szenario zu komplex, lässt sich aber sehr einfach sowohl mit dem UNPIVOT anwenden und PIVOT Funktionen in SQL Server.

Wenn Sie jedoch keinen Zugriff auf diese Funktionen haben, kann dies mit UNION ALL repliziert werden zu UNPIVOT und dann eine Aggregatfunktion mit einem CASE -Anweisung an PIVOT :

Tabelle erstellen:

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, Gesamt- und CASE-Version:

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

Siehe SQL Fiddle mit Demo

Die UNION ALL führt das UNPIVOT durch der Daten durch Transformieren der Spalten Paul, John, Tim, Eric in getrennte Reihen. Dann wenden Sie die Aggregatfunktion sum() an mit dem case -Anweisung, um die neuen Spalten für jede color zu erhalten .

Unpivot- und Pivot-Static-Version:

Sowohl das UNPIVOT und PIVOT Funktionen in SQL Server machen diese Transformation viel einfacher. Wenn Sie alle Werte kennen, die Sie transformieren möchten, können Sie sie in eine statische Version hartcodieren, um das Ergebnis zu erhalten:

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

Siehe SQL Fiddle mit Demo

Die innere Abfrage mit dem UNPIVOT erfüllt dieselbe Funktion wie UNION ALL . Es nimmt die Liste der Spalten und wandelt sie in Zeilen um, den PIVOT führt dann die endgültige Umwandlung in Spalten durch.

Dynamische Pivot-Version:

Wenn Sie eine unbekannte Anzahl von Spalten haben (Paul, John, Tim, Eric in Ihrem Beispiel) und dann eine unbekannte Anzahl von Farben zu transformieren, können Sie dynamisches SQL verwenden, um die Liste für UNPIVOT zu generieren und dann 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)

Siehe SQL Fiddle mit Demo

Die dynamische Version fragt sowohl yourtable und dann die sys.columns Tabelle, um die Liste der Elemente für UNPIVOT zu generieren und PIVOT . Dies wird dann zu einer auszuführenden Abfragezeichenfolge hinzugefügt. Der Vorteil der dynamischen Version ist, wenn Sie eine sich ändernde Liste von colors haben und/oder names dies erzeugt die Liste zur Laufzeit.

Alle drei Abfragen führen zum gleichen Ergebnis:

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