使用SQL Server将行数据转换为列数据

时间:2017-05-25 09:40:17

标签: sql-server

我想将行数据转换为列,其中列名不是来自数据。我认为使用Pivot不会给我正确的解决方案。请参阅我的数据的图像以及我希望它的外观。

enter image description here

示例中返回的行数将随着时间的推移而持续增长。

我的解决方案: 基于@Triv回答,我设法使用rank函数创建一个新列,然后使用动态数据透视SQL转换数据来解决问题。

2 个答案:

答案 0 :(得分:0)

您可以使用动态sql + PIVOT

CREATE TABLE #SampleData
(
   AccountNumber int,
   Product varchar(20),
   ProductEndDate datetime
)

INSERT INTO #SampleData VALUES (1,'Fixed 10','2016-01-01'),(1,'Fixed 11','2016-02-01'),(1,'Fixed 13','2016-03-01'),(1,'Fixed 12','2016-04-01'),
                        (2,'Fixed 10','2016-01-01'),(2,'Fixed 11','2016-02-01'),(2,'Fixed 13','2016-03-01')

DECLARE @HeaderAll nvarchar(max)
DECLARE @ColumnPivotProduct nvarchar(max)
DECLARE @ColumnPivotProductEndDate nvarchar(max)

;WITH temp AS
(
   SELECT DISTINCT 
   CONCAT('Product' ,row_number() OVER(PARTITION BY sd.AccountNumber ORDER BY sd.Product)) AS ProductGroup,
   CONCAT('ProductEndDate' ,row_number() OVER(PARTITION BY sd.AccountNumber ORDER BY sd.Product)) AS ProductEndDateGroup
   FROM #SampleData sd
)
SELECT @HeaderAll = STUFF((SELECT CONCAT(',',t.ProductGroup,'= MAX(',t.ProductGroup, '),', t.ProductEndDateGroup ,'= MAX(', t.ProductEndDateGroup,')') FROM temp t FOR XML PATH('')), 1,1,''),
     @ColumnPivotProduct =  STUFF((SELECT CONCAT(',',t.ProductGroup) FROM temp t FOR XML PATH('')), 1,1,''),
     @ColumnPivotProductEndDate =  STUFF((SELECT CONCAT(',', t.ProductEndDateGroup) FROM temp t FOR XML PATH('')), 1,1,'')

--SELECT @HeaderAll, @ColumnPivotProduct, @ColumnPivotProductEndDate


DECLARE @query nvarchar(max) = CONCAT(
      ';WITH temp AS
         (
            SELECT *, 
            CONCAT(''Product'' ,row_number() OVER(PARTITION BY sd.AccountNumber ORDER BY sd.Product)) AS ProductGroup,
            CONCAT(''ProductEndDate'' ,row_number() OVER(PARTITION BY sd.AccountNumber ORDER BY sd.Product)) AS ProductEndDateGroup
            FROM #SampleData sd
         )
      SELECT AccountNumber, ',@HeaderAll,' FROM           
          (
            SELECT t.AccountNumber, t.Product, t.ProductEndDate, t.ProductGroup,t.ProductEndDateGroup FROM temp t
          ) src
          PIVOT
          (
            MIN(Product) FOR ProductGroup IN (',@ColumnPivotProduct,')    
          ) pvt
          PIVOT
          (
            MIN(ProductEndDate) FOR ProductEndDateGroup IN (',@ColumnPivotProductEndDate,')    
          ) pvt1
      GROUP BY AccountNumber           
       ')

PRINT @query
exec(@query)


DROP TABLE #SampleData

演示链接:http://rextester.com/AEQBZ56634

注意:CONCAT可用于sql-server 2012+。如果您使用的是旧版本,请使用+连接字符串

答案 1 :(得分:0)

它有效,检查一下,而不是@testTable使用你的表名

 declare @temptable varchar(1000) = 'declare @tempTable1 table (',

@inserStatement varchar(1000) = 'insert into @tempTable1 (',

@insertValues varchar(1000) = ''

DECLARE @AcountNumber VARCHAR(50),@Product varchar(40),@ProductEndData varchar(50), @increment int = 0;

DECLARE db_cursor CURSOR FOR  
select 
Product,
ProductEndData from @testTable  

OPEN db_cursor   
FETCH NEXT FROM db_cursor INTO @Product, @ProductEndData 

WHILE @@FETCH_STATUS = 0   
BEGIN   
set @increment = @increment+1;
       SET @temptable += 'Product'+ cast(@increment as varchar) +' varchar(100),' + 'Product' + cast(@increment as varchar) + 'EndDate varchar(100),' ;
        set @inserStatement += 'Product'+ cast(@increment as varchar) +',' + 'Product' + cast(@increment as varchar) + 'EndDate,';

      set @insertValues += '(''' + @Product +''''+ ',' + ''''+ @ProductEndData + '''' + ')';


       FETCH NEXT FROM db_cursor INTO  @Product, @ProductEndData   

END   

CLOSE db_cursor   
DEALLOCATE db_cursor

set @temptable = STUFF(@temptable, LEN(@temptable), 1, ')')
set  @inserStatement = STUFF(@inserStatement, LEN(@inserStatement), 1, ')')
set @insertValues = replace(@insertValues, ')(', ',')
exec (@temptable + @inserStatement + ' values ' +  @insertValues + 'select * from @tempTable1')