sql >> Base de Datos >  >> RDS >> Sqlserver

Cómo transformar datos de filas basadas en una columna específica a otra estructura de datos

Puede usar unpivot/pivot para obtener el resultado que desea. Hay algunas formas diferentes de obtener el resultado, si tiene un número limitado de valores, puede codificar la consulta, pero si tiene un número desconocido de valores, necesitará usar SQL dinámico.

El proceso UNPIVOT convertirá las múltiples columnas de c1 , etc` en varias filas. Una vez que los datos están en varias filas, puede aplicar fácilmente la función PIVOT. Puede usar la función de no pivotar o APLICACIÓN CRUZADA para convertir los datos de varias columnas:

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)

Consulte SQL Fiddle con demostración . La aplicación cruzada convertirá sus datos al formato:

| 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 |

Una vez que los datos estén en este formato, puede aplicar 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;

Consulte SQL Fiddle con demostración .

Luego, si tiene un número desconocido de valores, puede convertir la consulta anterior a SQL dinámico:

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;

Consulte SQL Fiddle con demostración . Ambos darán un resultado:

| ID | SERVICEA_C1_1 | SERVICEA_CN_1 | SERVICEB_C1_2 | SERVICEB_CN_2 |
|  1 |             5 |             3 |             2 |             1 |
|  2 |             9 |             4 |        (null) |        (null) |