sql >> Databasteknik >  >> RDS >> Sqlserver

Hur man transformerar data från rader baserade på en specifik kolumn till en annan datastruktur

Du kan använda unpivot/pivot för att få det resultat du vill ha. Det finns några olika sätt som du kan få resultatet på, om du har ett begränsat antal värden kan du hårdkoda frågan men om du har ett okänt antal värden måste du använda dynamisk SQL.

UNPIVOT-processen kommer att konvertera de flera kolumnerna i c1 , etc` i flera rader. När data finns i flera rader kan du enkelt använda PIVOT-funktionen. Du kan använda unpivot-funktionen eller CROSS APPLY för att konvertera data från flera kolumner:

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)

Se SQL-fiol med demo . Korset tillämpas omvandlar din data till formatet:

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

När data är i detta format kan du använda 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;

Se SQL-fiol med demo .

Om du sedan har ett okänt antal värden kan du konvertera ovanstående fråga till dynamisk 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;

Se SQL-fiol med demo . Båda ger ett resultat:

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



  1. MySQL-fel 1241:Operand bör innehålla 1 kolumn(er)

  2. Symfony 2:INNER JOIN på icke-relaterad tabell med doktrinfrågebyggaren

  3. Kan en lagrad procedur/funktion returnera en tabell?

  4. PÅ DUBLIKAT NYCKELUPPDATERING implementering/design