我有一个结果集,我希望通过Service
列“展平”。
示例将最好地解释:
给定此结果集(让我们称之为request
):
---------------------------------------
| Id | Service | C1 | ... | Cn |
--------------------------------------|
| 1 | A | 5 | | 3 |
--------------------------------------|
| 1 | B | 2 | | 1 |
--------------------------------------|
| 2 | A | 9 | | 4 |
--------------------------------------
我想得到这个:
---------------------------------------------------------------------------
| Id | ServiceA_C1 | ... | ServiceA_Cn |ServiceB_C1 | ... | ServiceB_C2n |
---------------------------------------------------------------------------
| 1 | 5 | ... | 3 | 2 | ... | 1 |
---------------------------------------------------------------------------
| 2 | 9 | ... | 4 | NULL | ... | NULL |
---------------------------------------------------------------------------
最终预期结果:
n
列当前的解决方案(有效,但超长但效率不高):
SELECT A.C1 AS ServiceA_C1, ..,A.Cn AS ServiceA_Cn,B.C1 AS ServiceB_C1, ..,B.Cn AS ServiceB_Cn
FROM (SELECT *
FROM request
WHERE Service = 'A') AS A
JOIN
(SELECT *
FROM request
WHERE Service = 'B') AS B
ON A.Id = B.Id
注意:
服务数量约为10(Service
列中的#distinct值),
这是问题本身的通用措辞。
我知道SQL操作,如pivot,unpivot,cross apply,join等,但这个问题仍然让我烦恼,因为我没有找到一些棘手的东西来立即解决这个问题。我很高兴知道其中一种方法解决了这个问题,我错过了它。
由于
答案 0 :(得分:2)
您可以使用unpivot / pivot来获得所需的结果。有几种不同的方法可以获得结果,如果您的值有限,那么您可以对查询进行硬编码,但如果您有未知数量的值,那么您将需要使用动态SQL。
UNPIVOT流程会将c1
等多个列转换为多行。一旦数据在多行中,您就可以轻松应用PIVOT功能。您可以使用unpivot函数或CROSS APPLY来转换多列中的数据:
select id,
col = 'Service'+Service+'_'+col+'_'+cast(seq as varchar(10)),
value
from
(
select id, service, c1, cn
, row_number() over(partition by id
order by service) seq
from yourtable
) t
cross apply
(
select 'c1', c1 union all
select 'cn', cn
) c (col, value)
见SQL Fiddle with Demo。交叉应用会将您的数据转换为以下格式:
| ID | COL | VALUE |
| 1 | ServiceA_c1_1 | 5 |
| 1 | ServiceA_cn_1 | 3 |
| 1 | ServiceB_c1_2 | 2 |
| 1 | ServiceB_cn_2 | 1 |
| 2 | ServiceA_c1_1 | 9 |
| 2 | ServiceA_cn_1 | 4 |
一旦数据采用这种格式,您就可以应用PIVOT:
select id, ServiceA_c1_1, ServiceA_cn_1,
ServiceB_c1_2, ServiceB_cn_2
from
(
select id,
col = 'Service'+Service+'_'+col+'_'+cast(seq as varchar(10)),
value
from
(
select id, service, c1, cn
, row_number() over(partition by id
order by service) seq
from yourtable
) t
cross apply
(
select 'c1', c1 union all
select 'cn', cn
) c (col, value)
) d
pivot
(
max(value)
for col in (ServiceA_c1_1, ServiceA_cn_1,
ServiceB_c1_2, ServiceB_cn_2)
) piv;
然后,如果您有未知数量的值,则可以将上述查询转换为动态SQL:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME('Service'+Service+'_'+col+'_'+cast(seq as varchar(10)))
from
(
select service,
row_number() over(partition by id
order by service) seq
from yourtable
)d
cross apply
(
select 'c1', 1 union all
select 'cn', 2
) c (col, so)
group by seq, Service, col, so
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT id, ' + @cols + '
from
(
select id,
col = ''Service''+Service+''_''+col+''_''+cast(seq as varchar(10)),
value
from
(
select id, service, c1, cn
, row_number() over(partition by id
order by service) seq
from yourtable
) t
cross apply
(
select ''c1'', c1 union all
select ''cn'', cn
) c (col, value)
) x
pivot
(
max(value)
for col in (' + @cols + ')
) p '
execute sp_executesql @query;
见SQL Fiddle with Demo。两者都会给出结果:
| ID | SERVICEA_C1_1 | SERVICEA_CN_1 | SERVICEB_C1_2 | SERVICEB_CN_2 |
| 1 | 5 | 3 | 2 | 1 |
| 2 | 9 | 4 | (null) | (null) |