[英]Pivoting on two comma delimited columns
我为此苦苦挣扎,我在表中有两个字段,一个包含标题名称,另一个包含结果
例如,
ResultID TestID MemberID HeaderDefinition ResultDefinition
1 1 1 Minutes Exercised|KJ Burnt 60|900
2 2 1 Height|Weight|BMI 142|94|35
3 1 2 Minutes Exercised|KJ Burnt 70|1000
4 2 3 Height|Weight|BMI 150|60|20
我想做的是传递一个TestID并看到它在页眉上旋转
例如。 测试1
MemberID Minutes Exercised KJ Burnt
1 60 900
2 70 1000
例如。 测试2
MemberID Height Weight BMI
1 142 94 35
3 150 60 20
我已经看过所有标准的Pivoting示例和动态数据,但是它使用相同的字段工作,我需要一个字段来定义标题,另一个字段来定义结果,并且不确定如何将它们结合到上面的示例中,这有什么帮助将不胜感激。
我不能顺便更改数据的结构。
提前致谢。
我认为PIVOT无法正常工作; 那是用于将列切换为行,反之亦然。 在您的示例中,单列中有(可变数量的)列,并用竖线字符(|)分隔。
因此,您需要先做一些准备工作。 这项准备工作取决于您有多少个不同的测试,以及单个列中可以有多少个不同的列。 如果只是上面示例中带有2列或3列的两个测试,则可以“硬编码”一个或两个查询以提取数据。 如果它的可变性更大,则可能需要一个游标或临时表来完成更复杂的准备工作。
因此,这是一个使用2个查询的硬编码集的示例,您将不得不进行一些小的调整以使用表数据而不是变量:
declare @TestID int, @ResultDefinition varchar(100), @MemberID int
set @TestID = 1
set @MemberID = 1
if @TestID = 1 begin
set @ResultDefinition = '60|900'
select @MemberID,
LEFT(@ResultDefinition, CHARINDEX('|', @ResultDefinition)-1) AS [Minutes Exercised],
SUBSTRING(@ResultDefinition, CHARINDEX('|', @ResultDefinition)+1, LEN(@ResultDefinition)) AS [KJ Burnt]
--from tblResults
--where TestID = @TestID
end else begin
set @ResultDefinition = '142|94|35'
select @MemberID,
LEFT(@ResultDefinition, CHARINDEX('|', @ResultDefinition)-1) AS [Height],
LEFT(SUBSTRING(@ResultDefinition, charindex('|', @ResultDefinition) + 1, LEN(@ResultDefinition) ), charindex('|', SUBSTRING(@ResultDefinition, charindex('|', @ResultDefinition) + 1, LEN(@ResultDefinition) ))-1) as [Weight],
reverse(left(reverse(@ResultDefinition), CHARINDEX('|', reverse(@ResultDefinition))-1)) as [BMI]
--from tblResults
--where TestID = @TestID
end
如果比这更复杂,那么...我什至不想去那里! :)将涉及动态地建立一个表结构,然后用相关数据填充它,然后选择内容。
也许其他人有一个更优雅的解决方案...
如果您还实现类似于以下的Split函数,则可以使用PIVOT
来完成:
分割功能 :
CREATE FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))
returns @temptable TABLE (items varchar(MAX))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end;
然后,如果知道要转换为列的值,则可以使用静态枢轴对值进行硬编码:
select *
from
(
select h.memberid,
h.cols,
r.results
from
(
select t1.resultid,
t1.testid,
t1.memberid,
h.items cols,
row_number() over(partition by memberid order by memberid) rn
from table1 t1
cross apply dbo.split(t1.headerdefinition, '|') h
where t1.testid = 1
) h
left join
(
select t1.resultid,
t1.testid,
t1.memberid,
r.items results,
row_number() over(partition by memberid order by memberid) rn
from table1 t1
cross apply dbo.split(t1.resultdefinition, '|') r
where t1.testid = 1
) r
on h.memberid = r.memberid
and h.rn = r.rn
) x
pivot
(
max(results)
for cols in ([Minutes Exercised], [KJ Burnt])
) p
但是我将猜测您将要使用动态PIVOT
因为每个条目的列数都不同。 您的代码将与此类似:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX),
@testid int = 2
select @cols =
STUFF((SELECT ',' + QUOTENAME(x.cols)
from
(
select h.items cols,
row_number() over(partition by memberid order by memberid) rn
from table1 t1
cross apply dbo.split(t1.headerdefinition, '|') h
where t1.testid = @testid
) x
group by cols, rn
order by rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query
= 'SELECT memberid, ' + @cols + ' from
(
select h.memberid,
h.cols,
r.results
from
(
select t1.resultid,
t1.testid,
t1.memberid,
h.items cols,
row_number() over(partition by memberid order by memberid) rn
from table1 t1
cross apply dbo.split(t1.headerdefinition, ''|'') h
where t1.testid = '+ cast(@testid as varchar(10)) +'
) h
left join
(
select t1.resultid,
t1.testid,
t1.memberid,
r.items results,
row_number() over(partition by memberid order by memberid) rn
from table1 t1
cross apply dbo.split(t1.resultdefinition, ''|'') r
where t1.testid = '+ cast(@testid as varchar(10)) +'
) r
on h.memberid = r.memberid
and h.rn = r.rn
) x
pivot
(
max(results)
for cols in ('+@cols+')
) p'
execute(@query)
然后,根据@testid
传递的结果将是:
| MEMBERID | MINUTES EXERCISED | KJ BURNT |
-------------------------------------------
| 1 | 60 | 900 |
| 2 | 70 | 1000 |
要么
| MEMBERID | HEIGHT | WEIGHT | BMI |
------------------------------------
| 1 | 142 | 94 | 35 |
| 3 | 150 | 60 | 20 |
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.