我有一个返回行中数据的查询,我需要更改结果,因此结果是列而不是行。我做过研究并发现this文章有一个可以使用的动态查询,但似乎我的情况似乎不能使用该解决方案。该解决方案似乎依赖于每一行都有一个可用作列名的唯一名称,我没有。
我的数据包含客户对我们工厂的访问的客户记录。有些客户只会看到我们一次,有些客户会在同一时间段内多次看到我们,因此我们无法预测在给定时间段内每位客户的访问次数。注意ID 10219只有一次访问,5180有3次,5199有很多次。
ID Task Visit Date RF Score PF Score
10219 Follow Up Visit 12/26/2013 1 6
5180 Initial Visit 6/9/2011 3 9
5180 Follow Up Visit 7/8/2011 3 10
5180 Follow Up Visit 9/2/2011 1 10
5199 Follow Up Visit 9/15/2011 2 7
5199 Follow Up Visit 9/8/2011 5 6
5199 Follow Up Visit 10/27/2011 4 7
5199 Follow Up Visit 10/20/2011 2 4
5199 Follow Up Visit 10/13/2011 4 8
5199 Follow Up Visit 11/17/2011 3 4
5199 Follow Up Visit 11/10/2011 2 5
5199 Follow Up Visit 11/3/2011 3 3
对于像这样结构化的数据,任何人都知道如何动态地将这些行转换为列,即使我不知道需要多少列?
编辑:最终结果应如下所示:
ID Task1 Visit Date1 RF Score1 PF Score1 Task2 Visit Date2 RF Score2 PF Score2 Task3 Visit Date3 RF Score3 PF Score3
5180 Initial Visit 6/9/2011 3 9 Follow Up Visit 7/8/2011 3 10 Follow Up Visit 9/2/2011 1 10
答案 0 :(得分:2)
solution that you link to适用于您的情况,但您必须稍微调整它,因为您想要转向多列数据。由于您需要转动多个列,因此您首先要将Visit Date
,Task
,Rf Score
和Pf Score
列拆分为多行,然后应用pivot功能。除了取消隐私的过程之外,我还建议使用windowing function之类的row_number
来为每个id
生成一个具有日期的唯一序列。
您将使用以下内容开始查询:
select id, task, [visit date], [rf score], [pf score],
row_number() over(partition by id
order by [visit date]) seq
from yourtable
见SQL Fiddle with Demo。这会创建一个数字,用于将Visit Date
,Task
,Rf Score
和Pf Score
中的每个值与实际访问次数相关联。
获得此行号后,您将需要将多列拆分为多行数据。有几种方法可以做到这一点,包括使用unpivot功能。但是,由于您使用的是SQL Server 2008R2,因此可以将CROSS APPLY
与VALUES
一起使用:
select id,
col = col + cast(seq as varchar(10)),
value
from
(
select id, task, [visit date], [rf score], [pf score],
row_number() over(partition by id
order by [visit date]) seq
from yourtable
) d
cross apply
(
values
('VisitDate', convert(varchar(10), [visit date], 120)),
('Task', [task]),
('RfScore', cast([rf score] as varchar(10))),
('PfScore', cast([pf score] as varchar(10)))
) c (col, value)
见SQL Fiddle with Demo。您的数据现在采用可以轻松转动的格式:
| ID | COL | VALUE |
|-------|------------|-----------------|
| 5180 | VisitDate1 | 2011-06-09 |
| 5180 | Task1 | Initial Visit |
| 5180 | RfScore1 | 3 |
| 5180 | PfScore1 | 9 |
| 5180 | VisitDate2 | 2011-07-08 |
| 5180 | Task2 | Follow Up Visit |
| 5180 | RfScore2 | 3 |
| 5180 | PfScore2 | 10 |
添加PIVOT时的代码将是:
select id,
VisitDate1, Task1, RfScore1, PfScore1,
VisitDate2, Task2, RfScore2, PfScore2,
VisitDate3, Task3, RfScore3, PfScore3,
VisitDate4, Task4, RfScore4, PfScore4,
VisitDate5, Task5, RfScore5, PfScore5,
VisitDate6, Task6, RfScore6, PfScore6
from
(
select id,
col = col + cast(seq as varchar(10)),
value
from
(
select id, task, [visit date], [rf score], [pf score],
row_number() over(partition by id
order by [visit date]) seq
from yourtable
) d
cross apply
(
values
('VisitDate', convert(varchar(10), [visit date], 120)),
('Task', [task]),
('RfScore', cast([rf score] as varchar(10))),
('PfScore', cast([pf score] as varchar(10)))
) c (col, value)
) d
pivot
(
max(value)
for col in (VisitDate1, Task1, RfScore1, PfScore1,
VisitDate2, Task2, RfScore2, PfScore2,
VisitDate3, Task3, RfScore3, PfScore3,
VisitDate4, Task4, RfScore4, PfScore4,
VisitDate5, Task5, RfScore5, PfScore5,
VisitDate6, Task6, RfScore6, PfScore6)
) piv;
如果你的数值有限,上面的工作很有用,但如果它们未知,那么你需要使用动态SQL,上面的代码将被转换为:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(col + cast(seq as varchar(10)))
from
(
select row_number() over(partition by id
order by [visit date]) seq
from yourtable
) d
cross apply
(
select 'VisitDate', 1 union all
select 'Task', 2 union all
select 'RfScore', 3 union all
select 'PfScore', 4
) c (col, so)
group by seq, col, so
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'select id, ' + @cols + '
from
(
select id,
col = col + cast(seq as varchar(10)),
value
from
(
select id, task, [visit date], [rf score], [pf score],
row_number() over(partition by id
order by [visit date]) seq
from yourtable
) d
cross apply
(
values
(''VisitDate'', convert(varchar(10), [visit date], 120)),
(''Task'', task),
(''RfScore'', cast([rf score] as varchar(10))),
(''PfScore'', cast([pf score] as varchar(10)))
) c (col, value)
) s
pivot
(
max(value)
for col in (' + @cols + ')
) p '
execute sp_executesql @query;
见SQL Fiddle with Demo。两个版本都给出了结果:
| ID | VISITDATE1 | TASK1 | RFSCORE1 | PFSCORE1 | VISITDATE2 | TASK2 | RFSCORE2 | PFSCORE2 | VISITDATE3 | TASK3 | RFSCORE3 | PFSCORE3 | VISITDATE4 | TASK4 | RFSCORE4 | PFSCORE4 | VISITDATE5 | TASK5 | RFSCORE5 | PFSCORE5 | VISITDATE6 | TASK6 | RFSCORE6 | PFSCORE6 | VISITDATE7 | TASK7 | RFSCORE7 | PFSCORE7 | VISITDATE8 | TASK8 | RFSCORE8 | PFSCORE8 |
|-------|------------|-----------------|----------|----------|------------|-----------------|----------|----------|------------|-----------------|----------|----------|------------|-----------------|----------|----------|------------|-----------------|----------|----------|------------|-----------------|----------|----------|------------|-----------------|----------|----------|------------|-----------------|----------|----------|
| 5180 | 2011-06-09 | Initial Visit | 3 | 9 | 2011-07-08 | Follow Up Visit | 3 | 10 | 2011-09-02 | Follow Up Visit | 1 | 10 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |
| 5199 | 2011-09-08 | Follow Up Visit | 5 | 6 | 2011-09-15 | Follow Up Visit | 2 | 7 | 2011-10-13 | Follow Up Visit | 4 | 8 | 2011-10-20 | Follow Up Visit | 2 | 4 | 2011-10-27 | Follow Up Visit | 4 | 7 | 2011-11-03 | Follow Up Visit | 3 | 3 | 2011-11-10 | Follow Up Visit | 2 | 5 | 2011-11-17 | Follow Up Visit | 3 | 4 |
| 10219 | 2013-12-26 | Follow Up Visit | 1 | 6 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |