This seems like it should be a common need, but I'm not seeing how to do this using T-SQL PIVOT function. Specifically, I want to calculate the AVG and STDEV for a column over a Pivot column value. The data look something like this (lots of data omitted, but this gets to the heart):
这似乎应该是一个常见的需求,但我没有看到如何使用T-SQL PIVOT函数来做到这一点。具体来说,我想在Pivot列值上计算列的AVG和STDEV。数据看起来像这样(省略了大量数据,但这触及了心脏):
--------------------------------------------------------------------------
ID Year PersonID Score
--------------------------------------------------------------------------
106 2001 1 20
107 2002 1 30
108 2003 1 40
109 2004 1 50
106 2002 2 20
107 2003 2 50
108 2004 2 30
109 2005 2 10
--------------------------------------------------------------------------
I would like to see the following output
我想看看以下输出
--------------------------------------------------------------------------
NonPivotCol1 NonPivotCol2 2001_Mean 2001_Avg 2002_Mean 2002_Avg Etc
--------------------------------------------------------------------------
Some Value Some Value 32 5.2 28 3.1
Etc.
--------------------------------------------------------------------------
Do I need to revert to the old CASE statement logic?
我是否需要恢复旧的CASE语句逻辑?
Thanks!
3 个解决方案
#1
4
Yes.
Just use the old style CASE
syntax.
只需使用旧式CASE语法。
SELECT AVG(CASE WHEN Year = 2001 THEN Score END) AS 2001_Avg,
STDEV(CASE WHEN Year = 2001 THEN Score END) AS 2001_StDev /*...*/
PIVOT
is just (less versatile) syntactic sugar for this anyway.
无论如何,PIVOT只是(不太通用的)语法糖。
Oracle supports multiple aggregates in PIVOT
but TSQL doesn't.
Oracle支持PIVOT中的多个聚合,但TSQL不支持。
#2
2
use case statements. You have to specify all columns anyway and I'd say that case is more usable than pivot
用例陈述。无论如何你必须指定所有列,我会说这个案例比pivot更有用
select
avg(case when [Year] = 2001 then [Score] else null end) as [2001_Avg],
avg(case when [Year] = 2002 then [Score] else null end) as [2002_Avg]
from Table1
#3
0
You have to make two PIVOTs and join them
你必须制作两个PIVOT并加入它们
WITH MinPivot AS
(
SELECT
[2001] AS [2001_MEAN],
[2002] AS [2002_MEAN],
[2003] AS [2003_MEAN],
[2004] AS [2004_MEAN],
[2005] AS [2005_MEAN]
FROM
(
SELECT Year,Score
FROM Table1
) As S
PIVOT
(
STDEV(Score)
FOR Year in([2001],[2002],[2003],[2004],[2005])
)
AS pvt
),
AvgPivot AS
(
SELECT
[2001] AS [2001_AVG],
[2002] AS [2002_AVG],
[2003] AS [2003_AVG],
[2004] AS [2004_AVG],
[2005] AS [2005_AVG]
FROM
(
SELECT Year,Score
FROM Table1
) As S
PIVOT
(
AVG(Score)
FOR Year in([2001],[2002],[2003],[2004],[2005])
)
AS pvt
)
SELECT *
FROM MinPivot M
CROSS JOIN AvgPivot A
Have a look at this fiddle example
看看这个小提琴的例子
#1
4
Yes.
Just use the old style CASE
syntax.
只需使用旧式CASE语法。
SELECT AVG(CASE WHEN Year = 2001 THEN Score END) AS 2001_Avg,
STDEV(CASE WHEN Year = 2001 THEN Score END) AS 2001_StDev /*...*/
PIVOT
is just (less versatile) syntactic sugar for this anyway.
无论如何,PIVOT只是(不太通用的)语法糖。
Oracle supports multiple aggregates in PIVOT
but TSQL doesn't.
Oracle支持PIVOT中的多个聚合,但TSQL不支持。
#2
2
use case statements. You have to specify all columns anyway and I'd say that case is more usable than pivot
用例陈述。无论如何你必须指定所有列,我会说这个案例比pivot更有用
select
avg(case when [Year] = 2001 then [Score] else null end) as [2001_Avg],
avg(case when [Year] = 2002 then [Score] else null end) as [2002_Avg]
from Table1
#3
0
You have to make two PIVOTs and join them
你必须制作两个PIVOT并加入它们
WITH MinPivot AS
(
SELECT
[2001] AS [2001_MEAN],
[2002] AS [2002_MEAN],
[2003] AS [2003_MEAN],
[2004] AS [2004_MEAN],
[2005] AS [2005_MEAN]
FROM
(
SELECT Year,Score
FROM Table1
) As S
PIVOT
(
STDEV(Score)
FOR Year in([2001],[2002],[2003],[2004],[2005])
)
AS pvt
),
AvgPivot AS
(
SELECT
[2001] AS [2001_AVG],
[2002] AS [2002_AVG],
[2003] AS [2003_AVG],
[2004] AS [2004_AVG],
[2005] AS [2005_AVG]
FROM
(
SELECT Year,Score
FROM Table1
) As S
PIVOT
(
AVG(Score)
FOR Year in([2001],[2002],[2003],[2004],[2005])
)
AS pvt
)
SELECT *
FROM MinPivot M
CROSS JOIN AvgPivot A
Have a look at this fiddle example
看看这个小提琴的例子