【问题标题】:SQL Server PIVOT on key-value table键值表上的 SQL Server PIVOT
【发布时间】:2010-12-29 16:49:55
【问题描述】:

我有一个表,它具有基于键值的属性。示例:

CREATE TABLE ObjectAttributes
(
  int objectId, key nvarchar(64), value nvarchar(512)
)

当我从中选择时,我得到:

objectId  key      value
----------------------------
1         Key 1    Value 1
1         Key 2    Value 2

我想知道是否可以使用 PIVOT 语法将其转换为:

objectId  Key 1     Key 2
---------------------------
1         Value 1   Value 2

我知道我所有的桌子都有相同的键。 (不幸的是,我不能轻易更改表结构。这就是导致我尝试使用 PIVOTS 的原因。

这里最大的问题是枢轴需要使用聚合函数。有没有办法避免这种情况?尝试这个我完全错了吗?还是有更好的解决方案?

【问题讨论】:

  • 您想要固定列输出吗?也就是说,您想旋转给定 objectid 的所有键?

标签: sql-server-2005 pivot


【解决方案1】:

对于固定列输出,枢轴不会比重复自连接更快。

SELECT
   T1.objectID, T1.Value AS Key1, T2.Value AS Key2
FROM
   ObjectAttributes T1
   JOIN
   ObjectAttributes T2 ON T1.objectID = T2.objectID
WHERE
   T1.key = 'Key 1'
   AND
   T2.key = 'Key 2'

如果您想使用 PIVOT,那么只需使用 MAX。因为每个对象/键都有一行,所以无论如何它都是微不足道的,并且可以满足 PIVOT 要求。

如果您想将 未知 行数 PIVOT 到列中,那么它是动态 SQL(根据 SQL Server 2000 解决方案)或在客户端代码中执行。

如果每个对象都有固定数量的属性,那么我会考虑使用第二个表,其中包含由触发器维护的真实列。笨拙,但让阅读更轻松

【讨论】:

  • 嗯,好的。我假设数据透视表背后有某种魔力让它更快。我将使用自加入路线。
  • 您可能希望为此解决方案使用外连接。如果您缺少一个键,那么整行输出 objectID 将与此处使用的内部连接一起消失。
【解决方案2】:

不,您无法避免聚合。 SQL Server 需要某种方式将许多可能的行组合成一个值。您碰巧只有一个值,但 PIVOT 功能是考虑到许多行。

SELECT objectId, [Key 1], [Key 2]
FROM
(SELECT objectId, [key], value FROM ObjectAttributes) AS source
PIVOT
(
 MIN(value)
 FOR [key] IN ([Key 1], [Key 2])
) as pvt

【讨论】:

    【解决方案3】:

    我正在添加这个答案,因为这个帖子是第一个出现在谷歌上的关于这个问题的帖子之一。

    我发现的最简单的解决方案是使用 max 与 case 的组合,如下所示:

    -- Pivot the data with a handwritten T-SQL statement.
    -- Make sure you have an index defined on the grouping column.
    SELECT
        RecordID,
        -- Spreading and aggregation phase
        MAX(CASE WHEN Element = 'FirstName' THEN Value END) AS 'FirstName',
        MAX(CASE WHEN Element = 'LastName' THEN Value END) AS 'LastName',
        MAX(CASE WHEN Element = 'City' THEN Value END) AS 'City',
        MAX(CASE WHEN Element = 'Country' THEN Value END) AS 'Country'
    FROM EAVTable
    GROUP BY RecordID -- Grouping phase
    

    参考:https://www.sqlpassion.at/archive/2014/08/25/the-dangerous-beauty-of-the-pivot-operator-in-sql-server/

    此解决方案几乎适用于所有人,如果您需要旋转许多列,则无需大量加入

    【讨论】:

    • 使用'MAX'功能的原因是什么?谢谢
    【解决方案4】:
    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT ',' + QUOTENAME(your_key_column) 
                        from YOUR_ORIGINAL_KEY_AND_VALUE_TABLE
                        group by your_key_column
                        FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT your_row_heading_columns,' + @cols + '
                INTO YOUR_NEW_PIVOTED_TABLE
                from 
                (
                  select your_row_heading_columns,your_key_column,your_value_column
                  from YOUR_ORIGINAL_KEY_AND_VALUE_TABLE
                ) x
                pivot 
                (
                    max(your_value_column)
                    for your_key_column in (' + @cols + ')
                ) p '
    
    execute sp_executesql @query;
    

    【讨论】:

      猜你喜欢
      • 2012-06-17
      • 2014-03-20
      • 1970-01-01
      • 1970-01-01
      • 2017-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多