Sql 将多行中的数据转换为单行(值不是标准值)
我的问题是: 我有一张有姓名和地址的桌子Sql 将多行中的数据转换为单行(值不是标准值),sql,sql-server-2008,tsql,pivot,Sql,Sql Server 2008,Tsql,Pivot,我的问题是: 我有一张有姓名和地址的桌子 Name | Address | Updated ---------------------------------- a | 12 lane | 1/1/2011 b | 34 avenue | 1/1/2011 c | 56 district | 1/1/2011 a | 78 avenue | 8/8/2011 b | 90 lane |
Name | Address | Updated
----------------------------------
a | 12 lane | 1/1/2011
b | 34 avenue | 1/1/2011
c | 56 district | 1/1/2011
a | 78 avenue | 8/8/2011
b | 90 lane | 8/8/2011
a | 83 district | 9/9/2011
a | 39 road | 10/10/2011
正如你所看到的,人们有可能有多个地址。假设一个人最多有5个地址
我只对每个人最新的3个地址感兴趣,这样表就会如下所示:
Name | Address_1 | Address_2 | Address_3
--------------------------------------------------------------
a | 78 avenue | 83 district | 39 road
b | 34 avenue | 90 lane | NULL
c | 56 district | NULL | NULL
请注意,a的第一个条目“12车道”没有出现
我已经阅读了stackoverflow上显示的其他示例,但我不确定Pivot表是否适合我所需要的,因为地址都不同
提前感谢您提供的任何帮助 你可以旋转它。关键点是按更新的降序为地址分配行号。这将生成列名称1、2和3(以及4、5-但这些将被pivot命令忽略)
下面是一个使用
ROW\u NUMBER()
因为您只需要三个地址列,所以这可能是合适的。该解决方案不适用于非固定数量的列
;with testdata(Name, Address, Updated)
as
(
select 'a','12 lane',convert(datetime, '1/1/2011')
union all
select 'b','34 avenue',convert(datetime, '1/1/2011')
union all
select 'c','56 district',convert(datetime, '1/1/2011')
union all
select 'a','78 avenue',convert(datetime, '8/8/2011')
union all
select 'b','90 lane',convert(datetime, '8/8/2011')
union all
select 'a','83 district',convert(datetime, '9/9/2011')
union all
select 'a','39 road',convert(datetime, '10/10/2011')
)
,tmp
as
(
select *
,row_number() over(PARTITION by Name order by Updated desc) as rn
from testdata
)
select x.Name
,x.Address
,y.Address
,z.Address
from tmp x
left join tmp y
on x.Name = y.Name
and y.rn = 2
left join tmp z
on x.Name = z.Name
and z.rn = 3
where x.rn = 1
可以考虑使用两个查询:
- 第一种方法是使用DISTINCT键获取唯一的“名称”
- 第二个,在唯一名称的循环中,使用TOP子句(在您的例子中是TOP 3)和“ORDER BY Updated DESC”规范获取每个名称的3个最新地址
- 当然,可以使用合适的联接组合查询
;with testdata(Name, Address, Updated)
as
(
select 'a','12 lane',convert(datetime, '1/1/2011')
union all
select 'b','34 avenue',convert(datetime, '1/1/2011')
union all
select 'c','56 district',convert(datetime, '1/1/2011')
union all
select 'a','78 avenue',convert(datetime, '8/8/2011')
union all
select 'b','90 lane',convert(datetime, '8/8/2011')
union all
select 'a','83 district',convert(datetime, '9/9/2011')
union all
select 'a','39 road',convert(datetime, '10/10/2011')
)
,tmp
as
(
select *
,row_number() over(PARTITION by Name order by Updated desc) as rn
from testdata
)
select x.Name
,x.Address
,y.Address
,z.Address
from tmp x
left join tmp y
on x.Name = y.Name
and y.rn = 2
left join tmp z
on x.Name = z.Name
and z.rn = 3
where x.rn = 1