旋转两列,使表中的其他列保持不变

时间:2013-03-13 03:06:40

标签: sql sql-server tsql pivot sql-server-2012

我想知道是否可以在SQL Server 2012中完成以下操作。

我有以下数据:

Product_ID    Date     Attribute    Value
-------------------------------------------
10025135       2009    Colour       Red
10025135       2009    Size         20 cm
10025135       2009    Material     Steel
10025135       2010    Colour       Green
10025135       2010    Size         NULL
10025135       2010    Material     Alloy
10025136       2009    Colour       Black
10025136       2009    Size         30cm
10025136       2009    Material     NULL

我想检索数据,以便它们显示如下:

Product_ID    Date    Colour    Size     Material
-------------------------------------------------
10025135       2009   Red       20 cm    Steel
10025135       2010   Green     NULL     Alloy
10025136       2009   Black     30 cm    NULL

我试图让它们无法成功。

2 个答案:

答案 0 :(得分:4)

SELECT   Product_ID, Date, Colour, Size, Material
FROM
        (
            SELECT  Product_ID, Date, Attribute, Value
            FROM    Table1
        ) org
        PIVOT
        (
            MAX(Value)
            FOR Attribute IN (Colour, Size, Material)
        ) pivotHeader

输出

╔════════════╦══════╦════════╦════════╦══════════╗
║ PRODUCT_ID ║ DATE ║ COLOUR ║  SIZE  ║ MATERIAL ║
╠════════════╬══════╬════════╬════════╬══════════╣
║   10025135 ║ 2009 ║ Red    ║ 20 cm  ║ Steel    ║
║   10025135 ║ 2010 ║ Green  ║ (null) ║ Alloy    ║
║   10025136 ║ 2009 ║ Black  ║ 30cm   ║ (null)   ║
╚════════════╩══════╩════════╩════════╩══════════╝

另一种方法是使用MAX()CASE

SELECT  Product_ID, DATE,
        MAX(CASE WHEN Attribute = 'Colour' THEN Value END ) Colour,
        MAX(CASE WHEN Attribute = 'Size' THEN Value END ) Size,
        MAX(CASE WHEN Attribute = 'Material' THEN Value END ) Material
FROM    Table1
GROUP   BY Product_ID, DATE

答案 1 :(得分:1)

您可以使用PIVOT功能来实现所需的结果。这将获取attribute列中的行值并将其转换为列。

执行此操作时要考虑的主要事项是您是否具有已知或未知数量的attribute值。

如果提前知道这些值,那么您可以使用静态PIVOT对值进行硬编码:

select product_id,
  Colour,
  Size,
  Material
from 
(
  select product_id, date, attribute, value
  from yourtable
) src
pivot
(
  max(value)
  for attribute in (Colour, Size, Material)
) piv;

请参阅SQL Fiddle with Demo

但是如果attribute列的值未知或需要是动态的,那么您将需要实现动态SQL。动态SQL将获取要在SQL字符串中使用的列的列表。

获取列列表的代码与此类似:

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(attribute) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

此查询的结果是:

[Colour],[Material],[Size] 

这会在执行时创建应转换为列的attributes列表,并将其连接到执行的最终字符串中。您为动态SQL数据透镜的代码是:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(attribute) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT product_id,' + @cols + ' 
             from 
             (
                select product_id, date, attribute, value
                from yourtable
             ) x
             pivot 
             (
                max(value)
                for attribute in (' + @cols + ')
             ) p '

execute(@query)

请参阅SQL Fiddle with Demo

两个查询的结果是:

| PRODUCT_ID | COLOUR |   SIZE | MATERIAL |
-------------------------------------------
|   10025135 |    Red |  20 cm |    Steel |
|   10025136 |  Black |   30cm |   (null) |
|   10025135 |  Green | (null) |    Alloy |