键值表上的SQL Server PIVOT

时间:2010-12-29 16:49:56

标签: sql-server-2005 pivot

我有一个基于键值的属性表。例如:

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的原因。)

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

4 个答案:

答案 0 :(得分:10)

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

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要求。

如果要将未知行数存储到列中,则它是动态SQL(根据SQL Server 2000解决方案)或在客户端代码中执行。

如果每个对象具有固定数量的属性,那么我会考虑使用由触发器维护的实数列的第二个表。笨拙,但让生活更容易阅读

答案 1 :(得分:6)

不,你无法避免聚合。 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

答案 2 :(得分:0)

我要添加此答案,因为此线程是Google上针对该问题出现的第一个线程。

我发现的最简单的解决方案是使用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/

该解决方案几乎也适用于所有人,如果需要旋转许多列,则不需要太多的连接

答案 3 :(得分:0)

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;