是否可以使用 SQL Server 使用相同的数据透视列进行多个数据透视

Posted

技术标签:

【中文标题】是否可以使用 SQL Server 使用相同的数据透视列进行多个数据透视【英文标题】:Is it possible to have multiple pivots using the same pivot column using SQL Server 【发布时间】:2013-02-22 20:02:43 【问题描述】:

我正面临以下挑战。我需要在同一列上旋转表数据两次。 这是数据的截图。

我想为每个项目 ID 设置一行,其中包含每年的购买价值和销售价值。 我尝试通过选择“年份”列两次,对其进行格式化,以便每个销售年份以“S”为前缀,每个采购年份以“P”开头,并使用 2 个枢轴围绕 2 年列旋转.这是 SQL 查询(用于 SQL Server 2008):

SELECT [Item ID], 
        [P2000],[P2001],[P2002],[P2003],
        [S2000],[S2001],[S2002],[S2003]
FROM 
(

SELECT [Item ID]
      ,'P' + [Year] AS YearOfPurchase
      ,'S' + [Year] AS YearOfSelling

  ,[Purchasing value]
  ,[Selling value]
  FROM [ItemPrices]
) AS ALIAS

PIVOT 
(
MIN ([Purchasing value]) FOR [YearOfPurchase] in ([P2000],[P2001],[P2002],[P2003])
)
AS pvt

PIVOT 
(
MIN ([Selling value]) FOR [YearOfSelling] in ([S2000],[S2001],[S2002],[S2003])
)
AS pvt2

结果并不是我所希望的(见下图):

如您所见,每个项目 ID 仍然不止一行。有没有办法将行数减少到每个项目正好一个?这样看起来有点像下面的 Excel 截图?

【问题讨论】:

正是我需要的问题——我自己会问类似的问题! 【参考方案1】:

我的建议是同时应用 UNPIVOTPIVOT 函数来获得结果。

UNPIVOT 会将PurchasingValueSellingValue 列转换为行。完成此操作后,您可以将数据转换为结果。

代码将是:

select *
from
(
  select itemid, 
    case 
      when col = 'PurchasingValue' then 'P'
      when col = 'SellingValue' then 'S'
    end + cast(year as varchar(4)) new_col,
    value
  from yourtable
  unpivot
  (
    value
    for col in ([PurchasingValue], [SellingValue])
  ) unpiv
) src
pivot
(
  max(value)
  for new_col in (P2000, P2001, P2002, P2003,
                  S2000, S2001, S2002, S2003)
) piv;

见SQL Fiddle with Demo。结果是:

| ITEMID | P2000 | P2001 | P2002 | P2003 | S2000 | S2001 | S2002 | S2003 |
--------------------------------------------------------------------------
|      1 |  1000 |  1100 |  1200 |  1300 |   900 |   990 |  1080 |  1170 |
|      2 |   500 |   550 |   600 |   650 |   450 |   495 |   540 |   585 |

在 SQL Server 2008+ 中,您可以使用 CROSS APPLYVALUES 以及 PIVOT 函数:

select *
from
(
  select itemid,
    col+cast(year as varchar(4)) new_col,
    value
  from yourtable
  cross apply
  (
    VALUES
        (PurchasingValue, 'P'),
        (SellingValue, 'S')
   ) x (value, col)
) src
pivot
(
  max(value)
  for new_col in (P2000, P2001, P2002, P2003,
                  S2000, S2001, S2002, S2003)
) piv

见SQL Fiddle with Demo

【讨论】:

感谢 unpivot 建议。我没有想到这一点(并且不确定将来是否会这样:-)) @RobVermeulen 是的,unpivot 函数效果很好。我刚刚用一个也使用cross apply 的版本更新了我的答案。两者都会得到相同的结果。 @RobVermeulen 这很难说,这真的取决于很多因素。如果您担心速度,则应尝试查询的不同变体,以确定最适合您的情况。 我知道谢谢你的帖子不受欢迎,但我只想告诉你非常感谢!先生,你救了我的一周。在到达这篇文章之前,我发现的唯一解决方案是在同一张表上旋转两次,然后加入它们,但由于某种原因,第二个枢轴在连接的笛卡尔积上运行,而不是在表本身上运行,所以只要行数超过1000,执行时间飞涨。所以只有在知道 unpivot 的存在(感谢你)之后,我才能解决我的问题。干杯! @Alain 如果您使用 CROSS APPLY 版本,那么您可以将值转换/转换为相同的数据类型。【参考方案2】:

透视多个列的一种简单方法是仅使用 Aggregate(Case) 表达式。

SELECT  [Item ID],
        [P2000] = SUM(CASE WHEN [Year] = 2000 THEN [Purchasing value] END),
        [P2001] = SUM(CASE WHEN [Year] = 2001 THEN [Purchasing value] END),
        [P2002] = SUM(CASE WHEN [Year] = 2002 THEN [Purchasing value] END),
        [P2003] = SUM(CASE WHEN [Year] = 2003 THEN [Purchasing value] END),
        [S2000] = SUM(CASE WHEN [Year] = 2000 THEN [Selling value] END),
        [S2001] = SUM(CASE WHEN [Year] = 2001 THEN [Selling value] END),
        [S2002] = SUM(CASE WHEN [Year] = 2002 THEN [Selling value] END),
        [S2003] = SUM(CASE WHEN [Year] = 2003 THEN [Selling value] END)
FROM    ItemPrices
GROUP BY [Item ID]

【讨论】:

【参考方案3】:

使用 GROUP BY ItemID,并在每个结果列上使用聚合函数 SUM(isnull(value,0))。

【讨论】:

以上是关于是否可以使用 SQL Server 使用相同的数据透视列进行多个数据透视的主要内容,如果未能解决你的问题,请参考以下文章

雪花是不是支持 sql server 中使用的几何数据类型?

是否可以同时更新 SQL Server 数据库和 Informix 数据库?

是否可以使用 Pymssql 通过域(Windows)用户帐户远程访问 SQL Server 2012

从脚本文件夹创建或调整 SQL Server 数据库

SQL Server 中是不是有一种方法可以显示两个具有相同布局并共享一些公共数据的表之间的字段差异

sql server 触发器 从一个表添加到另个表是否两个表对应的字段必须相同呢