T-SQL'de PIVOT işlevini anlama


83

SQL'de çok yeniyim.

Bunun gibi bir masam var:

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

Ve bunun gibi verileri almam söylendi

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

PIVOT işlevini kullanmam gerektiğini anlıyorum. Ama açıkça anlayamıyorum. Yukarıdaki durumda (veya varsa herhangi bir alternatif) birisinin bunu açıklayabilmesi çok yardımcı olur.

Yanıtlar:


109

Bir PIVOTbirden çok sütun içine bir sütundan veri döndürmek için kullanılabilir.

Örneğiniz için burada bir STATİK Pivot vardır, yani döndürmek istediğiniz sütunları sabit kodlarsınız:

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

İşte bir SQL Demosu çalışan bir sürümü olan .

Bu aynı zamanda dinamik bir sütun listesi oluşturduğunuz ve PIVOT'u gerçekleştirdiğiniz dinamik bir PIVOT aracılığıyla da yapılabilir.

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)

Her ikisi için sonuçlar:

ELEMENTID   PHASEID1    PHASEID5    PHASEID6
3           Null        6.74        8.25
4           2.23        6.8         1.5

1
Teşekkürler anladım. PhaseIDQUOTENAME'den önce kod yazmam gereken tek şey . sağ?
Web-E

1
QUOTENAME'de, değerleri hangi sütundan almanız gerektiğini belirlemeniz gerekir. Sorduğun bu mu?
Taryn

STUFF çözümünün garip sütun isimleriyle (boşluklar, parantezler vb.) Çalışmasını sağlamak için yapmam gerekiyordu SELECT distinct '],['ve ayrıca ifadenin sonunda1, 2, '') + ']'
Nat

@ Web-E, maalesef evet. Çözüm olarak, uygulamanızda sorgu dizesini yazabilir veya bir saklı yordamda dinamik SQL ile oynayabilirsiniz.
MarcoM

7

Bunlar çok basit pivot örnekleridir, nazikçe bunun üzerinden geçin.

SQL SERVER - PIVOT ve UNPIVOT Tablo Örnekleri

Ürün tablosu için yukarıdaki bağlantıdan örnek:

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

oluşturur:

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

Benzer örnekler, SQL Server'daki Pivot tabloları blog gönderisinde bulunabilir . Basit bir örnek


Ayrıca, kaynak tablodan fazladan sayısal sütun çekerseniz, pivotun sonuçları birçok satıra böldüğünü unutmayın. Örnek 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 Bunun çalışması için qtysütunu kaynaktan kaldırmanız gerekiyor
Raheel Hasan

4

Burada kimsenin bahsetmediği bir şey ekleyeceğim.

pivotOne for: Kaynak 3 sütun olduğunda işlev harika çalışıyor aggregate, birlikte sütun olarak yayılmasına birini forve bir pivot gibi birini rowdağılımı. Ürün örneğinde bu QTY, CUST, PRODUCT.

Bununla birlikte, kaynakta daha fazla sütununuz varsa, sonuçları ek sütun başına benzersiz değerlere göre pivot başına bir satır yerine birden çok satıra böler ( Group Bybasit bir sorguda olduğu gibi).

Bu örneğe bakın, kaynak tabloya bir zaman damgası sütunu ekledim:

görüntü açıklamasını buraya girin

Şimdi etkisini görün:

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

görüntü açıklamasını buraya girin


Bunu düzeltmek için, yukarıda herkesin yaptığı gibi bir alt sorguyu kaynak olarak çekebilirsiniz - sadece 3 sütunla (bu, senaryonuz için her zaman işe yaramayacak where, zaman damgası için bir koşul koymanız gerekip gerekmediğini düşünün ).

İkinci çözüm, a kullanmak group byve özetlenmiş sütun değerlerinin toplamını tekrar yapmaktır.

SELECT 
CUST, 
sum(MILK) t_MILK

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

GROUP BY CUST
ORDER BY CUST

GO

görüntü açıklamasını buraya girin


4

Veri kümenizdeki sütunlardan birini satırlardan sütunlara dönüştürmek için bir pivot kullanılır (bu genellikle yayma sütunu olarak adlandırılır ). Verdiğiniz örnekte bu, PhaseIDsatırları bir sütun kümesine dönüştürmek anlamına gelir ; burada her farklı değer için bir sütun vardır.PhaseID 1, 5 ve 6'yı içerebilen .

Bu özetlenmiş değerler, verdiğiniz örnekteki sütun aracılığıyla gruplandırılırElementID .

Tipik olarak ayrıca , size yayma değeri ( ) ile gruplama değerinin ( ) kesişimi tarafından referans verilen değerleri veren bir toplama biçimi sağlamanız gerekir . Verilen örnekte kullanılacak toplama net olmasa da sütunu içerir .PhaseIDElementIDEffort

Bu pivotlama yapıldıktan sonra, gruplama ve yayma sütunları bir toplama değeri bulmak için kullanılır . Veya sizin durumunuzda ElementIDve PhaseIDXarayın Effort.

Gruplama, yayma, toplama terminolojisini kullanarak, genellikle aşağıdaki gibi bir pivot için örnek sözdizimi görürsünüz:

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

Bu , daha fazla yardımcı olacaksa , gruplama, yayma ve toplama sütunlarının kaynaktan özet tablolara nasıl dönüştürüldüğüne dair grafiksel bir açıklama verir .


3

Uyumluluk hatasını ayarlamak için

pivot işlevini kullanmadan önce bunu kullanın

ALTER DATABASE [dbname] SET COMPATIBILITY_LEVEL = 100  

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

1
neden <SELECT query that produces the data>sadece masa değil?
Raheel Hasan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.