基于sql中表的行生成动态列

时间:2013-06-21 08:04:29

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

我有一个包含四列item_id,颜色,大小,重量的表,我想将我的表行显示为一行,如item1,color1,size1,weight1,item2,color2,......... ..,item4,color4,size4,weight4 ......

以下是我的表

+---------+--------+--------+--------+
| item_id | color  | size   | weight |
+---------+--------+--------+--------+
|       1 | blue   | large  | 65     |
|       2 | orange | large  | 57     |
|       3 | red    | small  | 12     |
|       4 | violet | medium | 34     |

我想要的结果将是

+---------+--------+--------+--------++---------+--------+--------+
| item_id1| color1| size1 | weight1| item_id2 | color2  | size2   | weight2 |....
+---------+--------+--------+--------+---------+--------+--------+---------------
|       1 | blue   | large| 65     |      2   | orange  | large   | 57      |...
+---------+--------+--------+--------+    +---------+--------+--------+--------+

提前致谢。

2 个答案:

答案 0 :(得分:3)

为了得到这个结果,你需要做一些事情:

  • UNPIVOT当前数据
  • PIVOT来自unpivot的结果
  • 使用动态SQL,因为您将拥有未知行数

由于您使用的是SQL Server 2005+,因此可以使用CROSS APPLY来取消数据的移动,此过程将使用item_idcolorsize和{{1}的多列并将它们转换为多行:

weight

SQL Fiddle with Demo。这给出了一个结果:

select col+'_'+cast(seq as varchar(50)) col,
     value
from 
(
   select item_id as seq, item_id, color, size, weight
   from yourtable
) d
cross apply
(
   values
    ('item_id', cast(item_id as varchar(50))),
    ('color', color),
    ('size', size),
    ('weight', cast(weight as varchar(50)))
) c (col, value);

从结果中可以看出,您现在有多个基于原始数据的行。 | COL | VALUE | ---------------------- | item_id_1 | 1 | | color_1 | blue | | size_1 | large | | weight_1 | 65 | | item_id_2 | 2 | | color_2 | orange | | size_2 | large | | weight_2 | 57 | | item_id_3 | 3 | 值是您将用于PIVOT的值。完整的动态SQL代码将类似于以下内容:

COL

SQL Fiddle with Demo。最终结果是:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(col+'_'+cast(item_id as varchar(10))) 
                    from yourtable
                    cross apply
                    (
                      select 'item_id', 0 union all
                      select 'color', 1 union all
                      select 'size', 2 union all
                      select 'weight', 3 
                    ) c (col, so)
                    group by item_id, col, so
                    order by item_id, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ' + @cols + ' 
            from 
            (
                select col+''_''+cast(seq as varchar(50)) col,
                  value
                from 
                (
                  select item_id as seq, item_id, color, size, weight
                  from yourtable
                ) d
                cross apply
                (
                  values
                    (''item_id'', cast(item_id as varchar(50))),
                    (''color'', color),
                    (''size'', size),
                    (''weight'', cast(weight as varchar(50)))
                ) c (col, value)
            ) x
            pivot 
            (
                max(value)
                for col in (' + @cols + ')
            ) p '

execute(@query);

答案 1 :(得分:2)

如果您想以编程方式执行此操作并且您不知道行数,请尝试以下操作:

DECLARE @I INT, @END INT, @DATA nvarchar(max), @TEMPSTR nvarchar(max), @DynamicTableSQL nvarchar(max)
SET @I = 1
SET @DATA = ''
SET @TEMPSTR = ''

SELECT @END = MAX(item_id) from items


SET @DynamicTableSQL = 'DECLARE @DynamicTable TABLE('
WHILE @I <= @END
BEGIN
    --SELECT @I
    SET @TEMPSTR = (select CAST(item_id as nvarchar) + ',''' + color + ''',''' + size + ''',' + cast(weight as nvarchar) + ',' FROM items WHERE item_id = @I)
    SET @DynamicTableSQL = @DynamicTableSQL + 'item_id_' + CAST(@I AS VARCHAR(10))+ ' INT ,' + 'color_' + CAST(@I AS VARCHAR(10))+ ' NVARCHAR(15) ,'+ 'size_' + CAST(@I AS VARCHAR(10))+ ' NVARCHAR(15) ,'+ 'weight_' + CAST(@I AS VARCHAR(10))+ ' INT ,'
    SET @DATA += @TEMPSTR
    SELECT @I = @I + 1
END

SET @DynamicTableSQL = SUBSTRING(@DynamicTableSQL, 0, LEN(@DynamicTableSQL))
SET @DynamicTableSQL = @DynamicTableSQL + ') '
SET @DATA = SUBSTRING(@DATA, 0, LEN(@DATA))
SET @DynamicTableSQL = @DynamicTableSQL + ' INSERT INTO @DynamicTable VALUES (' + @DATA + ')'

SET @DynamicTableSQL = @DynamicTableSQL + ' SELECT * FROM @DynamicTable '

EXEC SP_EXECUTESQL @DynamicTableSQL