我有以下数据:
DECLARE @DataSource TABLE
(
[ColumnA] INT
,[ColumnB] INT
,[ColumnC] INT
)
INSERT INTO @DataSource ([ColumnA], [ColumnB], [ColumnC])
VALUES (5060,1006,100118)
,(5060,1006,100119)
,(5060,1006,100120)
,(5060,1007,100121)
,(5060,1007,100122)
,(5060,1012,100123)
SELECT [ColumnA]
,[ColumnB]
,[ColumnC]
FROM @DataSource
我需要像这样转换:
困难的部分是数据是动态的(我不知道我将拥有多少列)并且我无法在此使用标准数据透视,因为ColumnC
中的值不同而且因此我将在ColumnC
中显示尽可能多的列。
有没有什么技术可以达到这个目的? 任何形式的帮助(答案,文章,建议)将不胜感激。
答案 0 :(得分:5)
我建议您在使用PIVOT时始终首先使用硬编码的值编写查询,然后您可以轻松地将查询转换为动态解决方案。
由于您将有多个columnC
值将转换为列,因此您需要查看使用row_number()
窗口函数为每个{{1}生成唯一序列}基于columnc
和columnA
的值。
您的查询的起点是:
columnB
见Demo。此查询将生成新列名称select [ColumnA],
[ColumnB],
[ColumnC],
'SampleTitle'+
cast(row_number() over(partition by columna, columnb
order by columnc) as varchar(10)) seq
from DataSource;
等的列表:
SampleTitle1
然后,您可以使用| COLUMNA | COLUMNB | COLUMNC | SEQ |
|---------|---------|---------|--------------|
| 5060 | 1006 | 100118 | SampleTitle1 |
| 5060 | 1006 | 100119 | SampleTitle2 |
| 5060 | 1006 | 100120 | SampleTitle3 |
中列出的新列名称在columnC
上应用数据透视:
seq
一旦拥有了正确的逻辑,就可以将数据转换为动态SQL。这里的关键是生成新列名列表。我通常使用select columnA, columnB,
SampleTitle1, SampleTitle2, SampleTitle3
from
(
select [ColumnA],
[ColumnB],
[ColumnC],
'SampleTitle'+
cast(row_number() over(partition by columna, columnb
order by columnc) as varchar(10)) seq
from DataSource
) d
pivot
(
max(columnc)
for seq in (SampleTitle1, SampleTitle2, SampleTitle3)
) piv;
,类似于:
FOR XML PATH
见Demo。获得列名列表后,您将生成要执行的sql字符串,完整代码将为:
select STUFF((SELECT distinct ',' + QUOTENAME(seq)
from
(
select 'SampleTitle'+
cast(row_number() over(partition by columna, columnb
order by columnc) as varchar(10)) seq
from DataSource
) d
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
见SQL Fiddle with Demo。结果如下:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(seq)
from
(
select 'SampleTitle'+
cast(row_number() over(partition by columna, columnb
order by columnc) as varchar(10)) seq
from DataSource
) d
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT columnA, ColumnB,' + @cols + '
from
(
select [ColumnA],
[ColumnB],
[ColumnC],
''SampleTitle''+
cast(row_number() over(partition by columna, columnb
order by columnc) as varchar(10)) seq
from DataSource
) x
pivot
(
max(columnc)
for seq in (' + @cols + ')
) p '
execute sp_executesql @query;