Sql 需要根据行中的日期将表数据选择到不同的列中
我不确定我在这里需要什么,看起来我可以使用枢轴,但我不认为这有那么复杂,如果可以的话,我想避免使用枢轴,因为我根本没有使用过它 我有这样的数据:Sql 需要根据行中的日期将表数据选择到不同的列中,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我不确定我在这里需要什么,看起来我可以使用枢轴,但我不认为这有那么复杂,如果可以的话,我想避免使用枢轴,因为我根本没有使用过它 我有这样的数据: ID score notes CreateDate 1661 9.2 8.0 on Sept 2010 7/22/2010 1661 7.6 11/4/2010 1661 7.9 6/
ID score notes CreateDate
1661 9.2 8.0 on Sept 2010 7/22/2010
1661 7.6 11/4/2010
1661 7.9 6/10/2011
1661 8.3 9/28/2011
1661 7.9 1/20/2012
ID score1 notes1 date1 score2 notes2 date2 score3 notes3 date3 score4 notes4 date4
1661 9.2 8.0 on Sept 2010 7/22/2010 7.6 blah 11/4/2010 7.9 blah2 6/10/2011 8.3 blah3 9/28/2011
我想将所有数据组织到一行,最早的日期在第一行,然后使用下一个最早的日期,然后是下一个最早的日期…直到我使用4或5个日期。所以最终的结果是这样的:
ID score notes CreateDate
1661 9.2 8.0 on Sept 2010 7/22/2010
1661 7.6 11/4/2010
1661 7.9 6/10/2011
1661 8.3 9/28/2011
1661 7.9 1/20/2012
ID score1 notes1 date1 score2 notes2 date2 score3 notes3 date3 score4 notes4 date4
1661 9.2 8.0 on Sept 2010 7/22/2010 7.6 blah 11/4/2010 7.9 blah2 6/10/2011 8.3 blah3 9/28/2011
在这种情况下,PIVOT会很棘手,因为如果您只想显示Score1、Score2、Score3等,那么每个测试PIVOT都有多个列。幸运的是,您可以使用CASE语句创建一个简单但冗长的解决方案:
select
ID,
max(case when RowNum = 1 then Score else null end) as Score1,
max(case when RowNum = 1 then Notes else null end) as Notes1,
max(case when RowNum = 1 then CreateDate else null end) as Date1,
max(case when RowNum = 2 then Score else null end) as Score2,
max(case when RowNum = 2 then Notes else null end) as Notes2,
max(case when RowNum = 2 then CreateDate else null end) as Date2,
max(case when RowNum = 3 then Score else null end) as Score3,
max(case when RowNum = 3 then Notes else null end) as Notes3,
max(case when RowNum = 3 then CreateDate else null end) as Date3,
max(case when RowNum = 4 then Score else null end) as Score4,
max(case when RowNum = 4 then Notes else null end) as Notes4,
max(case when RowNum = 4 then CreateDate else null end) as Date4,
max(case when RowNum = 5 then Score else null end) as Score5,
max(case when RowNum = 5 then Notes else null end) as Notes5,
max(case when RowNum = 5 then CreateDate else null end) as Date5
from
(
select
*, row_number() over (partition by ID order by CreateDate) as RowNum
from
mytable
) tt
group by
ID
这是硬编码,涵盖5项测试。少一点就可以了,但不会显示第六个。显然,您可以创建更多的CASE语句来处理更多的测试。正因为我喜欢PIVOT,我将向您展示如何使用PIVOT函数来实现这一点。为了获得PIVOT函数的结果,您首先需要取消PIVOT的多列score、notes和createdate。unpivot进程将多列转换为多行 由于您使用的是SQL Server 2008,因此可以使用交叉应用来取消对数据的归档,因此查询的第一部分类似于:
;with cte as
(
select id, score, notes, createdate,
row_number() over(partition by id order by createdate) seq
from yourtable
)
select id, col, value
from
(
select t.id,
col = col + cast(seq as varchar(10)),
value
from cte t
cross apply
(
values
('score', cast(score as varchar(10))),
('notes', notes),
('date', convert(varchar(10), createdate, 120))
) c (col, value)
) d;
看。执行此操作将以以下格式获取数据:
| ID | COL | VALUE |
| 1661 | score1 | 9.20 |
| 1661 | notes1 | 8.0 on Sept 2010 |
| 1661 | date1 | 2010-07-22 |
| 1661 | score2 | 7.60 |
| 1661 | notes2 | (null) |
| 1661 | date2 | 2010-11-04 |
| 1661 | score3 | 7.90 |
现在,您可以应用PIVOT函数:
;with cte as
(
select id, score, notes, createdate,
row_number() over(partition by id order by createdate) seq
from yourtable
)
select id, col, value
from
(
select t.id,
col = col + cast(seq as varchar(10)),
value
from cte t
cross apply
(
values
('score', cast(score as varchar(10))),
('notes', notes),
('date', convert(varchar(10), createdate, 120))
) c (col, value)
) d
pivot
(
max(value)
for col in (score1, notes1, date1, score2, notes2, date2,
score3, notes3, date3, score4, notes4, date4,
score5, notes5, date5)
) piv;
看
然后,如果每个id的值数目未知,则可以实现动态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 createdate) seq
from yourtable
) d
cross apply
(
select 'score', 1 union all
select 'notes', 2 union all
select 'date', 3
) 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 t.id,
col = col + cast(seq as varchar(10)),
value
from
(
select id, score, notes, createdate,
row_number() over(partition by id order by createdate) seq
from yourtable
) t
cross apply
(
values
(''score'', cast(score as varchar(10))),
(''notes'', notes),
(''date'', convert(varchar(10), createdate, 120))
) c (col, value)
) x
pivot
(
max(value)
for col in (' + @cols + ')
) p '
execute sp_executesql @query;
| ID | SCORE1 | NOTES1 | DATE1 | SCORE2 | NOTES2 | DATE2 | SCORE3 | NOTES3 | DATE3 | SCORE4 | NOTES4 | DATE4 | SCORE5 | NOTES5 | DATE5 |
| 1661 | 9.20 | 8.0 on Sept 2010 | 2010-07-22 | 7.60 | (null) | 2010-11-04 | 7.90 | (null) | 2011-06-10 | 8.30 | (null) | 2011-09-28 | 7.90 | (null) | 2012-01-20 |
看。两个版本都给出了结果:
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 createdate) seq
from yourtable
) d
cross apply
(
select 'score', 1 union all
select 'notes', 2 union all
select 'date', 3
) 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 t.id,
col = col + cast(seq as varchar(10)),
value
from
(
select id, score, notes, createdate,
row_number() over(partition by id order by createdate) seq
from yourtable
) t
cross apply
(
values
(''score'', cast(score as varchar(10))),
(''notes'', notes),
(''date'', convert(varchar(10), createdate, 120))
) c (col, value)
) x
pivot
(
max(value)
for col in (' + @cols + ')
) p '
execute sp_executesql @query;
| ID | SCORE1 | NOTES1 | DATE1 | SCORE2 | NOTES2 | DATE2 | SCORE3 | NOTES3 | DATE3 | SCORE4 | NOTES4 | DATE4 | SCORE5 | NOTES5 | DATE5 |
| 1661 | 9.20 | 8.0 on Sept 2010 | 2010-07-22 | 7.60 | (null) | 2010-11-04 | 7.90 | (null) | 2011-06-10 | 8.30 | (null) | 2011-09-28 | 7.90 | (null) | 2012-01-20 |
实际上,PIVOT在这里没有任何帮助,因为您不能在多个列上进行PIVOT。案例版本是两者中更灵活的一种。它可以缩短一点,否则null是多余的,因为这是默认行为。PIVOT是否可以按照OP的要求创建一行结果?@MartinSmith很好地说明了PIVOT不处理多个列。从技术上讲,可以从UNPIVOT开始,但是是的,它会变得混乱。@ExactaBox-它会变得非常混乱,因为数据类型是数字、日期和字符串。即使所有相同的数据类型都是UNPIVOT。。。PIVOT的效率比CASE要低。我说过如果可以的话我想避免PIVOT,但我并不反对使用它。也许我今天累了,不想再学习了。我会试试这个案例的解决方案,看看它能给我带来什么。如果您有一个pivot解决方案,我将看一看,因为这可能比实际情况更优雅。谢谢你。@ExactaBox我能说什么。