Grundlegendes zur PIVOT-Funktion in T-SQL

82

Ich bin sehr neu in SQL.

Ich habe einen Tisch wie diesen:

ID | TeamID | UserID | ElementID | PhaseID | Effort
-----------------------------------------------------
1  |   1    |  1      |   3       |  5     |   6.74
2  |   1    |  1      |   3       |  6     |   8.25
3  |   1    |  1      |   4       |  1     |   2.23
4  |   1    |  1      |   4       |  5     |   6.8
5  |   1    |  1      |   4       |  6     |   1.5

Und mir wurde gesagt, ich solle solche Daten bekommen

ElementID | PhaseID1 | PhaseID5 | PhaseID6
--------------------------------------------
    3     |   NULL   |   6.74   |   8.25
    4     |   2.23   |   6.8    |   1.5

Ich verstehe, dass ich die PIVOT-Funktion verwenden muss. Kann es aber nicht klar verstehen. Es wäre eine große Hilfe, wenn jemand dies im obigen Fall erklären könnte (oder gegebenenfalls Alternativen).

Wir sind
quelle

Antworten:

109

A wird PIVOTverwendet, um die Daten aus einer Spalte in mehrere Spalten zu drehen.

In Ihrem Beispiel ist hier ein STATISCHER Pivot, dh Sie codieren die Spalten, die Sie drehen möchten, fest:

create table temp
(
  id int,
  teamid int,
  userid int,
  elementid int,
  phaseid int,
  effort decimal(10, 5)
)

insert into temp values (1,1,1,3,5,6.74)
insert into temp values (2,1,1,3,6,8.25)
insert into temp values (3,1,1,4,1,2.23)
insert into temp values (4,1,1,4,5,6.8)
insert into temp values (5,1,1,4,6,1.5)

select elementid
  , [1] as phaseid1
  , [5] as phaseid5
  , [6] as phaseid6
from
(
  select elementid, phaseid, effort
  from temp
) x
pivot
(
  max(effort)
  for phaseid in([1], [5], [6])
)p

Hier ist eine SQL-Demo mit einer funktionierenden Version.

Dies kann auch über einen dynamischen PIVOT erfolgen, bei dem Sie die Liste der Spalten dynamisch erstellen und den PIVOT ausführen.

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.phaseid) 
            FROM temp c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT elementid, ' + @cols + ' from 
            (
                select elementid, phaseid, effort
                from temp
           ) x
            pivot 
            (
                 max(effort)
                for phaseid in (' + @cols + ')
            ) p '


execute(@query)

Die Ergebnisse für beide:

ELEMENTID   PHASEID1    PHASEID5    PHASEID6
3           Null        6.74        8.25
4           2.23        6.8         1.5
Taryn
quelle
1
Danke, verstanden. Einzige Sache, die ich PhaseIDvor QUOTENAME hart codieren muss. Recht?
Web-E
1
Im QUOTENAME müssen Sie angeben, aus welcher Spalte Sie die Werte abrufen möchten. Fragen Sie das?
Taryn
Damit die STUFF-Lösung mit seltsamen Spaltennamen (Leerzeichen, Klammern usw.) funktioniert SELECT distinct '],[', musste ich dies tun , und auch am Ende der Anweisung1, 2, '') + ']'
Nat
@ Web-E, leider ja. Um dieses Problem zu umgehen, können Sie die Abfragezeichenfolge in Ihre Anwendung schreiben oder mit dynamischem SQL in einer gespeicherten Prozedur spielen.
MarcoM
7

Dies sind die sehr grundlegenden Pivot-Beispiele.

Beispiele für SQL SERVER - PIVOT- und UNPIVOT-Tabellen

Beispiel vom obigen Link für die Produkttabelle:

SELECT PRODUCT, FRED, KATE
FROM (
SELECT CUST, PRODUCT, QTY
FROM Product) up
 PIVOT (SUM(QTY) FOR CUST IN (FRED, KATE)) AS pvt
ORDER BY PRODUCT

rendert:

 PRODUCT FRED  KATE
 --------------------
 BEER     24    12
 MILK      3     1
 SODA   NULL     6
 VEG    NULL     5

Ähnliche Beispiele finden Sie in den Pivot-Tabellen des Blogposts in SQL Server. Ein einfaches Beispiel

Shaikh Farooque
quelle
Beachten Sie außerdem, dass der Pivot die Ergebnisse in viele Zeilen aufteilt, wenn Sie eine zusätzliche numerische Spalte aus der Quelltabelle ziehen. Beispiel SELECT CUST, VEG, SODA FROM (SELECT rand() as x, CUST, PRODUCT, QTY FROM Product) up PIVOT ( SUM(x) FOR PRODUCT IN (VEG, SODA) ) AS pvt ORDER BY CUST GO Damit dies funktioniert, müssen Sie die qtySpalte aus der Quelle entfernen
Raheel Hasan
4

Ich muss hier etwas hinzufügen, das niemand erwähnt hat.

Die pivotFunktion funktioniert hervorragend, wenn die Quelle drei Spalten enthält: eine für die aggregate, eine als Spalte mit forund eine als Drehpunkt für die rowVerteilung. Im Produktbeispiel ist es QTY, CUST, PRODUCT.

Wenn Sie jedoch mehr Spalten in der Quelle haben, werden die Ergebnisse in mehrere Zeilen anstatt in eine Zeile pro Pivot aufgeteilt, basierend auf eindeutigen Werten pro zusätzlicher Spalte (wie Group Bydies bei einer einfachen Abfrage der Fall wäre).

In diesem Beispiel habe ich der Quelltabelle eine Zeitstempelspalte hinzugefügt:

Geben Sie hier die Bildbeschreibung ein

Jetzt sehen Sie seine Auswirkungen:

SELECT CUST, MILK

FROM Product
-- FROM (SELECT CUST, Product, QTY FROM PRODUCT) p
PIVOT (
    SUM(QTY) FOR PRODUCT IN (MILK)
) AS pvt

ORDER BY CUST

Geben Sie hier die Bildbeschreibung ein


Um dies zu beheben, können Sie entweder eine Unterabfrage als Quelle abrufen, wie dies alle oben getan haben - mit nur 3 Spalten (dies funktioniert in Ihrem Szenario nicht immer, stellen Sie sich vor, Sie müssen eine whereBedingung für den Zeitstempel festlegen).

Die zweite Lösung besteht darin, a zu verwenden group byund erneut eine Summe der geschwenkten Spaltenwerte zu erstellen.

SELECT 
CUST, 
sum(MILK) t_MILK

FROM Product
PIVOT (
    SUM(QTY) FOR PRODUCT IN (MILK)
) AS pvt

GROUP BY CUST
ORDER BY CUST

GO

Geben Sie hier die Bildbeschreibung ein

Raheel Hasan
quelle
4

Ein Schwenk wird verwendet , um aus Zeilen in Spalten in Ihrem Datensatz eine der Spalten zu konvertieren (dies ist in der Regel bezeichnet als die Verbreitung Spalte ). In dem von Ihnen angegebenen Beispiel bedeutet dies, dass die PhaseIDZeilen in eine Reihe von Spalten konvertiert werden , wobei für jeden einzelnen Wert eine Spalte vorhanden ist PhaseID, die in diesem Fall 1, 5 und 6 enthalten kann.

Diese geschwenkten Werte werden in dem von Ihnen angegebenen Beispiel über die Spalte gruppiertElementID .

In der Regel müssen Sie dann auch eine Form der Aggregation angeben , die Ihnen die Werte liefert, auf die durch den Schnittpunkt des Spreizwerts ( PhaseID) und des Gruppierungswerts ( ElementID) verwiesen wird . In dem gegebenen Beispiel ist die verwendete Aggregation zwar unklar, betrifft aber die EffortSpalte.

Sobald dieses Schwenken abgeschlossen ist, werden die Gruppierungs- und Spreizspalten verwendet, um einen Aggregationswert zu finden . Oder in Ihrem Fall ElementIDund PhaseIDXsuchen Effort.

Bei Verwendung der Terminologie für Gruppierung, Verteilung und Aggregation wird die Beispielsyntax für einen Pivot normalerweise wie folgt angezeigt:

WITH PivotData AS
(
    SELECT <grouping column>
        , <spreading column>
        , <aggregation column>
    FROM <source table>
)
SELECT <grouping column>, <distinct spreading values>
FROM PivotData
    PIVOT (<aggregation function>(<aggregation column>)
        FOR <spreading column> IN <distinct spreading values>));

Dies gibt eine grafische Erklärung, wie die Gruppierungs-, Spreiz- und Aggregationsspalten von der Quelle in schwenkbare Tabellen konvertiert werden, wenn dies weiter hilft.

t_warsop
quelle
3

Kompatibilitätsfehler einstellen

Verwenden Sie diese Option, bevor Sie die Pivot-Funktion verwenden

ALTER DATABASE [dbname] SET COMPATIBILITY_LEVEL = 100  
Easvarr
quelle
3
    SELECT <non-pivoted column>,
    [first pivoted column] AS <column name>,
    [second pivoted column] AS <column name>,
    ...
    [last pivoted column] AS <column name>
FROM
    (<SELECT query that produces the data>)
    AS <alias for the source query>
PIVOT
(
    <aggregation function>(<column being aggregated>)
FOR
[<column that contains the values that will become column headers>]
    IN ( [first pivoted column], [second pivoted column],
    ... [last pivoted column])
) AS <alias for the pivot table>
<optional ORDER BY clause>;

USE AdventureWorks2008R2 ;
GO
SELECT DaysToManufacture, AVG(StandardCost) AS AverageCost 
FROM Production.Product
GROUP BY DaysToManufacture;

    DaysToManufacture          AverageCost
0                          5.0885
1                          223.88
2                          359.1082
4                          949.4105

    -- Pivot table with one row and five columns
SELECT 'AverageCost' AS Cost_Sorted_By_Production_Days, 
[0], [1], [2], [3], [4]
FROM
(SELECT DaysToManufacture, StandardCost 
    FROM Production.Product) AS SourceTable
PIVOT
(
AVG(StandardCost)
FOR DaysToManufacture IN ([0], [1], [2], [3], [4])
) AS PivotTable;




Here is the result set.
Cost_Sorted_By_Production_Days    0         1         2           3       4       
AverageCost                       5.0885    223.88    359.1082    NULL    949.4105
user2211290
quelle
1
Warum ist der <SELECT query that produces the data>nicht nur Tisch?
Raheel Hasan