【问题标题】:SQL - Multiple PIVOT operator doesn't work with aliasSQL - 多个 PIVOT 运算符不适用于别名
【发布时间】:2019-10-16 21:36:56
【问题描述】:

测试数据:

CREATE table #user (ID INT)
insert into #user values (1)

CREATE table #type 
(
 subscriberId INT,
 typeId INT,
 typeValue NVARCHAR(256)
)
insert into #type values (1,1,'Type1')
insert into #type values (1,2,'Type2')
insert into #type values (1,3,'Type3')

CREATE table #category
(
 subscriberId INT,
 categoryId INT,
 categoryValue NVARCHAR(256)
)
insert into #category values (1,1,'Category1')
insert into #category values (1,4,'Category4')
insert into #category values (1,5,'Category5')
insert into #category values (1,6,'Category6')

我有一个查询,效果很好

SELECT * FROM (
SELECT t.subscriberId,
    t.typeId, t.typeValue,
    c.categoryId, c.categoryValue
    FROM #user u
    INNER JOIN #type t on t.subscriberId = u.id
    INNER JOIN #category c on c.subscriberId = u.id) target
PIVOT(
    max(typeValue)
    for typeId in ([1],[2],[3])
) as [pivot_table1]
PIVOT (
    max(categoryValue)
    for categoryId in ([4],[5],[6])
) as [pivot_table2]

但是当我尝试对 categoryId 和 typeId 使用相同的 Id 时:

for categoryId in ([1],[4],[5],[6])

我看到一个错误:

Msg 265, Level 16, State 1, Line 38 在中指定的列名“1” PIVOT 运算符与 枢轴论点。消息 8156,级别 16,状态 1,第 39 行“1”列 为“pivot_table2”指定了多次。

另外,我不能使用 [pivot_table1].[1]] 代替 * ,但是当我只使用一个 PIVOT 运算符时是可能的。 有人知道我该如何解决吗? 预期结果: 如何在两个 PIVOT 中使用相同的 id(列名)?

【问题讨论】:

  • 这看起来你最好使用交叉表;示例数据和预期结果将在这里真正有所帮助。
  • @Larnu 完成。准备再次审核
  • 你能提供预期的结果吗?
  • 感谢 @BasilKosovan 的 DDL 和 DML,这是提供样本数据的最佳方式,做得很好,但我们确实需要知道您的最终结果应该是什么。
  • @Larnu 预期结果是在两个 PIVOT 中使用相同的列名称。 PeterHe 已经提供了解决方案

标签: sql-server pivot


【解决方案1】:

被透视的列的值将是结果的列,因此它们不能具有相同的值以防止列名重复。您可以为类别的值添加前缀以区分它们:

SELECT * FROM (
SELECT t.subscriberId,
    t.typeId, t.typeValue,
    N'c_'+CAST(c.categoryId as nvarchar(22)) AS categoryId, c.categoryValue
    FROM #user u
    INNER JOIN #type t on t.subscriberId = u.id
    INNER JOIN #category c on c.subscriberId = u.id) target
PIVOT(
    max(typeValue)
    for typeId in ([1],[2],[3])
) as [pivot_table1]
PIVOT (
    max(categoryValue)
    for categoryId in (c_1, c_4, c_5, c_6)
) as [pivot_table2]

【讨论】:

  • 为什么不能使用 [pivot_table1].[1]什么时候没有列名冲突?
  • SQL Server 只能看到 PIVOT 的最后一个别名。它代表最终数据透视结果的所有列,例如您可以指定 SELECT [pivot_table2].[2]来自...
【解决方案2】:

如果 PeterHe 的答案提供了正确的返回数据集,那么(如前所述)交叉表似乎是更好的主意:

SELECT U.ID,
       MAX(CASE t.typeId WHEN 1 THEN t.typeValue END) AS [1],
       MAX(CASE t.typeId WHEN 2 THEN t.typeValue END) AS [2],
       MAX(CASE t.typeId WHEN 3 THEN t.typeValue END) AS [3],
       MAX(CASE c.categoryId WHEN 1 THEN c.categoryValue END) AS c_1,
       MAX(CASE c.categoryId WHEN 2 THEN c.categoryValue END) AS c_2, --Assumed wanted
       MAX(CASE c.categoryId WHEN 3 THEN c.categoryValue END) AS c_3, --Assumed wanted
       MAX(CASE c.categoryId WHEN 4 THEN c.categoryValue END) AS c_4,
       MAX(CASE c.categoryId WHEN 5 THEN c.categoryValue END) AS c_5,
       MAX(CASE c.categoryId WHEN 6 THEN c.categoryValue END) AS c_6
FROM #user u
     JOIN #type t ON u.ID = t.subscriberId
     JOIN #category c ON t.subscriberId = c.subscriberId
GROUP BY u.ID;

【讨论】:

  • 您必须明智地测试性能,但我从来没有遇到过比PIVOT、@BasilKosovan 更差的 Cross Tab。在我看来,交叉表比PIVOT 更容易理解;而且它更加灵活(正如您在此处看到的那样,您可以在同一个“呼吸”中对两个表进行旋转)。
  • 但是如果我需要按顺序使用这些列和 where 子句,它可能会很复杂
  • 真的不是,@BasilKosovan。如果您在WHERE 中需要它,请使用CTE,或使用HAVING 子句(即HAVING MAX(CASE t.typeId WHEN 3 THEN t.typeValue END) = 3)。列可以通过ORDER BY 中的别名引用;所以这不是问题。
猜你喜欢
  • 1970-01-01
  • 2016-12-04
  • 1970-01-01
  • 1970-01-01
  • 2011-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-10
相关资源
最近更新 更多