如果您知道要转换的列数,则可以使用anUNPIVOT
和 a来完成此操作,那么您可以使用静态版本:PIVOT
select *
from
(
select id, customerid, name, address,
col + '_'+ cast(rn as varchar(10)) col,
value
from
(
select c.id, customerid, c.name, c.address,
t.contactname,
cast(t.contact as varchar(20)) contact,
cast(t.id as varchar(20)) contactid,
row_number() over(partition by customerid order by customerid) rn
from customers c
left join contacts t
on c.id = t.customerid
) x
unpivot
(
value
for col in (ContactName, Contact, ContactId)
) u
) x1
pivot
(
min(value)
for col in ([ContactId_1], [ContactName_1], [Contact_1],
[ContactId_2], [ContactName_2], [Contact_2])
) p
见SQL Fiddle with Demo
但是,如果您不知道一条记录将有多少联系人,那么我会使用动态 SQL 来执行此操作:
DECLARE @colsPivot AS NVARCHAR(MAX),
@colsUnpivot AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
SET @colsUnPivot = stuff((select ','
+quotename(case when C.name = 'id' then'ContactId' else c.name end)
from sys.columns as C
where C.object_id = object_id('contacts') and
C.name <> 'CustomerId'
for xml path('')), 1, 1, '')
SET @colsPivot
= stuff((select ','+quotename(case when C.name = 'id' then'ContactId' else c.name end + '_' + cast(rn as varchar(10)))
from sys.columns as C
cross apply
(
select row_number() over(partition by customerid order by customerid) rn
from customers c
left join contacts t
on c.id = t.customerid
) x
where C.object_id = object_id('contacts') and
C.name <> 'CustomerId'
group by name, rn
order by rn
for xml path('')), 1, 1, '')
set @query
= '
select *
from
(
select id, customerid, name, address,
col + ''_''+ cast(rn as varchar(10)) col,
value
from
(
select c.id, customerid, c.name, c.address,
t.contactname,
cast(t.contact as varchar(20)) contact,
cast(t.id as varchar(20)) contactid,
row_number() over(partition by customerid order by customerid) rn
from customers c
left join contacts t
on c.id = t.customerid
) x1
unpivot
(
value
for col in (' + @colsUnPivot + ')
) unpvt
) x2
pivot
(
min(value)
for col in(' + @colsPivot +')
)p'
execute(@query)
见SQL Fiddle with Demo
两者都产生相同的结果。