PIVOT 动态地将行旋转到列中
Posted
技术标签:
【中文标题】PIVOT 动态地将行旋转到列中【英文标题】:PIVOT to pivot rows into columns dynamically 【发布时间】:2018-06-28 19:16:55 【问题描述】:我在每一行都有一张客户表及其购买类型和购买说明。
我想调整购买类型和备注,以便每一行只代表一个客户实例。
表格:
Customer ID | Name | Purchase Type | Purchase Notes
-------------+------+---------------+---------------
1 | John | Furniture | TextABC
1 | John | Appliance | TextDEF
1 | John | Accessory | TextGHI
目标:
Customer ID | Name | Purchase Type 1 | Purchase Notes 1 | Purchase Type 2| Purchase Notes 2 | Purchase Type 3 | Purchase Notes 3
------------ +------+-----------------+------------------+----------------+-------------------+-----------------+------------------
1 | John | Furniture |TextABC | Appliance | TextDEF | Accessory | TextGHI
要求:
我无法对任何购买类型或备注进行硬编码,因为它们可以更改。 我无法确定有多少种类型,因为它可能是 9 种或 4 种,具体取决于客户。
如何将编号添加到标题中,以便表格最多可以包含 x,但那些小于 x 的客户只会有空白?
阅读有关 SQL Pivot 的论坛,我似乎无法找到一种方法来做到这一点,而无需对其进行硬编码。
【问题讨论】:
【参考方案1】:你可以使用动态TSQL和PIVOT
:
if OBJECT_ID('dbo.test') is null
create table dbo.test (CustomerID int , [Name] varchar(50), PurchaseType varchar(50), PurchaseNotes varchar(50))
truncate table dbo.test
--populate test table
insert into dbo.test values
(1, 'John','Furniture','TextABC'), (1, 'John','Appliance','TextDEF'), (1, 'John','Accessory','TextGHI')
,(2, 'Mary','Furniture','TextJKL'), (2, 'Mary','Appliance','TextMNO'), (2, 'Mary','Accessory','TextPQR'), (2, 'Mary','New type','TextSTU')
declare @total int
declare @counter int = 1
declare @PurchaseNotes nvarchar(max)='' --holds all the PurchaseNotes column names
declare @PurchaseType nvarchar(max)='' --holds all the PurchaseType column names
declare @Combo nvarchar(max)='' --holds the combination of PurchaseType and PurchaseNotes for the final SELECT statement
declare @sql nvarchar(max)='' --contains the TSQL dinamically generated
--count distinct Purchase Types
select @total = count(distinct [PurchaseType]) from dbo.test
--build headers
while @counter <= @total
begin
set @PurchaseNotes = @PurchaseNotes + ' [PurchaseNotes' + cast(@counter as varchar(max)) + '],'
set @PurchaseType = @PurchaseType + ' [PurchaseType' + cast(@counter as varchar(max)) + '],'
set @Combo = @Combo + ' [PurchaseType' + cast(@counter as varchar(max)) + '],'+ ' [PurchaseNotes' + cast(@counter as varchar(max)) + '],'
set @counter = @counter + 1
end
set @PurchaseNotes = left(@PurchaseNotes,len(@PurchaseNotes)-1) + ' '
set @PurchaseType = left(@PurchaseType,len(@PurchaseType)-1)+ ' '
set @Combo = left(@Combo,len(@Combo)-1)+ ' '
--create dynamic TSQL query
set @sql = @sql + ' SELECT T.CustomerID, T.[Name],' + @Combo
set @sql = @sql + ' FROM '
set @sql = @sql + ' ( '
set @sql = @sql + ' SELECT [CustomerID],[Name],[PurchaseType],'
set @sql = @sql + ' CONCAT(''PurchaseType'',ROW_NUMBER() OVER (PARTITION BY customerid ORDER BY customerid, [Name])) AS COL '
set @sql = @sql + ' FROM dbo.test '
set @sql = @sql + ' ) SRC '
set @sql = @sql + ' PIVOT '
set @sql = @sql + ' ( '
set @sql = @sql + ' MAX(PurchaseType) '
set @sql = @sql + ' FOR COL IN (' + @PurchaseType + ') '
set @sql = @sql + ' ) AS T '
set @sql = @sql + ' inner join '
set @sql = @sql + ' ('
set @sql = @sql + ' SELECT * '
set @sql = @sql + ' FROM '
set @sql = @sql + ' ( '
set @sql = @sql + ' SELECT [CustomerID],[Name],[PurchaseNotes],'
set @sql = @sql + ' CONCAT(''PurchaseNotes'',ROW_NUMBER() OVER (PARTITION BY customerid ORDER BY customerid, [Name])) AS COL2 '
set @sql = @sql + ' FROM dbo.test '
set @sql = @sql + ' ) SRC '
set @sql = @sql + ' PIVOT '
set @sql = @sql + ' ( '
set @sql = @sql + ' MAX(PurchaseNotes) '
set @sql = @sql + ' FOR COL2 IN (' + @PurchaseNotes + ') '
set @sql = @sql + ' ) AS PVT2 '
set @sql = @sql + ' ) N'
set @sql = @sql + ' on T.CustomerID = N.CustomerID'
--execute dynamic query
exec (@sql)
输入(我用新的 PurchaseType 添加了另一个客户):
结果:
【讨论】:
以上是关于PIVOT 动态地将行旋转到列中的主要内容,如果未能解决你的问题,请参考以下文章