我有一张表格,其中包含个人开展的活动的详细信息 - 此表的内容类似于以下内容:
| Person | Category | Activity | -------------------------------------- | Username1 | X | X1 | | Username1 | Y | Y1 | | Username1 | Z | Z1 |
我需要一个SQL查询,它可以产生类似下面的内容,任何帮助都会受到赞赏:
| Person | Cat1 | Cat1_Act|Cat2 | Cat2_Act| Cat3 | Cat3_Act | --------------------------------------------------------------- | Username1 | X | X1 | Y | Y1 | Z | Z1 |
我理解阅读PIVOT可以用来实现这一目标的一些帖子但是我没有找到接近我需要的解决方案,因为大多数解决方案通常使用值,例如'X','Y', 'Z'(在我的示例表中)作为表标题,但我希望理想情况下能够为包含新列的表标题指定名称(希望这一切都有意义,有人可以帮助:-))
答案 0 :(得分:6)
有几种方法可以获得所需的结果。如果您希望将PIVOT分配到列中的值有限,则可以通过几种不同的方式对查询进行硬编码。
使用CASE的聚合函数:
select
person,
max(case when seq = 1 then category end) Cat1,
max(case when seq = 1 then activity end) Cat1_Act,
max(case when seq = 2 then category end) Cat2,
max(case when seq = 2 then activity end) Cat2_Act,
max(case when seq = 3 then category end) Cat3,
max(case when seq = 3 then activity end) Cat3_Act
from
(
select person, category, activity,
row_number() over(partition by person
order by category) seq
from yourtable
) d
group by person;
见SQL Fiddle with Demo。通过为每个用户的每个类别分配序列或row_number,您可以使用此行号将行转换为列。
静态PIVOT:
如果你想应用PIVOT函数,那么我首先会建议将category
和activity
列拆分为多行,然后应用pivot函数。
;with cte as
(
select person, category, activity,
row_number() over(partition by person
order by category) seq
from yourtable
)
select person,
cat1, cat1_act,
cat2, cat2_act,
cat3, cat3_act
from
(
select t.person,
col = case
when c.col = 'cat' then col+cast(seq as varchar(10))
else 'cat'+cast(seq as varchar(10))+'_'+col
end,
value
from cte t
cross apply
(
select 'cat', category union all
select 'act', activity
) c (col, value)
) d
pivot
(
max(value)
for col in (cat1, cat1_act, cat2, cat2_act,
cat3, cat3_act)
) piv;
动态PIVOT:最后,如果您有未知数量的值,那么您可以使用动态SQL来获得结果:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ','
+ QUOTENAME(case
when d.col = 'cat' then col+cast(seq as varchar(10))
else 'cat'+cast(seq as varchar(10))+'_'+col end)
from
(
select row_number() over(partition by person
order by category) seq
from yourtable
) t
cross apply
(
select 'cat', 1 union all
select 'act', 2
) d (col, so)
group by col, so, seq
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT person, ' + @cols + '
from
(
select t.person,
col = case
when c.col = ''cat'' then col+cast(seq as varchar(10))
else ''cat''+cast(seq as varchar(10))+''_''+col
end,
value
from
(
select person, category, activity,
row_number() over(partition by person
order by category) seq
from yourtable
) t
cross apply
(
select ''cat'', category union all
select ''act'', activity
) c (col, value)
) x
pivot
(
max(value)
for col in (' + @cols + ')
) p '
execute sp_executesql @query;
见SQL Fiddle with Demo。所有版本都给出了结果:
| PERSON | CAT1 | CAT1_ACT | CAT2 | CAT2_ACT | CAT3 | CAT3_ACT |
| Username1 | X | X1 | Y | Y1 | Z | Z1 |
答案 1 :(得分:2)
这是一个简单的例子
SELECT
Person,
MAX(CASE Category WHEN 'X' THEN Activity ELSE 0 END) AS 'X'
MAX(CASE Category WHEN 'Y' THEN Activity ELSE 0 END) AS 'Y'
MAX(CASE Category WHEN 'Z' THEN Activity ELSE 0 END) AS 'Z'
FROM mytable
GROUP BY Person