2013-10-02 13 views
0

行变换的数据我有我想通过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 | 
--------------------------------------------------------------------------- 

最终想要的结果:

  • 每个ID(其具有米ultiple值现在有一个排)
  • 服务的每个不同的值将有最终结果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值), 这是一个通用的pH问题本身的问题。

我知道像旋转,UNPIVOT,跨应用,联接等SQL操作,仍然这个问题让我很烦,因为我没有发现什么猫腻立即解决这个问题。我很高兴知道这种方法之一解决了这个问题,我错过了它。

谢谢

回答

2

您可以使用unpivot/pivot来获得所需的结果。有几种不同的方式,你可以得到的结果,如果你有值的数量有限,那么你可以硬编码查询,但如果你有一个未知的数值,那么你就需要使用动态SQL。

的UNPIVOT过程将多列转换的c1,etc`成多行。一旦数据在多行中,您就可以轻松应用PIVOT功能。您可以使用逆透视功能或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 Fiddle with Demo

然后,如果你有一个未知的数值,就可以在上面查询转换为动态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) | 
相关问题