了解T-SQL中的PIVOT函数

Web*_*b-E 68 t-sql sql-server pivot sql-server-2008

我是SQL新手.

我有这样一张桌子:

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
Run Code Online (Sandbox Code Playgroud)

我被告知要获得这样的数据

ElementID | PhaseID1 | PhaseID5 | PhaseID6
--------------------------------------------
    3     |   NULL   |   6.74   |   8.25
    4     |   2.23   |   6.8    |   1.5
Run Code Online (Sandbox Code Playgroud)

我明白我需要使用PIVOT功能.但无法清楚地理解它.如果有人能够在上面的案例中解释它,那将是很大的帮助.(或任何替代方案,如果有的话)

Tar*_*ryn 91

PIVOT用于从一个列中的数据旋转到多个列.

对于您的示例,这里是一个STATIC Pivot,意味着您要对要旋转的列进行硬编码:

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
Run Code Online (Sandbox Code Playgroud)

这是一个带有工作版本的SQL Demo.

这也可以通过动态PIVOT来完成,您可以在其中动态创建列列并执行PIVOT.

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)
Run Code Online (Sandbox Code Playgroud)

两者的结果:

ELEMENTID   PHASEID1    PHASEID5    PHASEID6
3           Null        6.74        8.25
4           2.23        6.8         1.5
Run Code Online (Sandbox Code Playgroud)


Sha*_*que 7

这些是非常基本的支点例子,请仔细考虑一下.

SQL SERVER - PIVOT和UNPIVOT表示例

产品表的上述链接示例:

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
Run Code Online (Sandbox Code Playgroud)

呈现:

 PRODUCT FRED  KATE
 --------------------
 BEER     24    12
 MILK      3     1
 SODA   NULL     6
 VEG    NULL     5
Run Code Online (Sandbox Code Playgroud)

类似的例子可以在SQL Server的博客文章Pivot表中找到.一个简单的样本


Rah*_*san 7

我要在这里添加一些没有人提到的东西。

pivot当源有 3 列时,该函数效果很好:一列用于aggregate,一列作为列传播,另一列for作为row分布的枢轴。在产品示例中,它是QTY, CUST, PRODUCT.

但是,如果源中有更多列,它将根据每个附加列的唯一值将结果分成多行而不是每个数据透视一行(就像Group By在简单查询中所做的那样)。

看这个例子,我在源表中添加了一个时间戳列:

在此处输入图片说明

现在看看它的影响:

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
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


为了解决这个问题,您可以像上面每个人所做的那样将子查询作为源提取 - 只有 3 列(这并不总是适用于您的场景,想象一下您是否需要where为时间戳设置条件)。

第二种解决方案是使用 agroup by并再次对旋转的列值求和。

SELECT 
CUST, 
sum(MILK) t_MILK

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

GROUP BY CUST
ORDER BY CUST

GO
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


t_w*_*sop 6

枢轴用于将数据集中的一列从行转换为列(这通常称为扩展列)。在您给出的示例中,这意味着将PhaseID行转换为一组列,PhaseID在这种情况下,每个不同的值都有一列可以包含 - 1、5 和 6。

这些枢轴值通过您提供的示例中的列进行分组ElementID

通常,您还需要提供某种形式的聚合,为您提供扩展值( PhaseID) 和分组值( ElementID)的交集所引用的。虽然在给出的示例中将使用的聚合不清楚,但涉及到Effort列。

完成此旋转后,将使用分组展开列来查找聚合值。或者在您的情况下,ElementIDPhaseIDX查找Effort.

使用分组、传播、聚合术语,您通常会看到枢轴的示例语法为:

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>));
Run Code Online (Sandbox Code Playgroud)

给出了分组、传播和聚合列如何从源转换为透视表的图形解释,如果这有进一步帮助的话。