sql >> Databáze >  >> RDS >> Sqlserver

Jak transformovat data z řádků na základě konkrétního sloupce do jiné datové struktury

K získání požadovaného výsledku můžete použít unpivot/pivot. Existuje několik různých způsobů, jak můžete získat výsledek, pokud máte omezený počet hodnot, můžete dotaz naprogramovat, ale pokud máte neznámý počet hodnot, budete muset použít dynamické SQL.

Proces UNPIVOT převede více sloupců c1 atd. do více řádků. Jakmile jsou data ve více řádcích, můžete snadno použít funkci PIVOT. K převodu dat z více sloupců můžete použít funkci unpivot nebo 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)

Viz SQL Fiddle s ukázkou . Křížové použití převede vaše data do formátu:

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

Jakmile budou data v tomto formátu, můžete použít 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;

Viz SQL Fiddle s ukázkou .

Pokud pak máte neznámý počet hodnot, můžete výše uvedený dotaz převést na dynamický 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;

Viz SQL Fiddle s ukázkou . Oba dají výsledek:

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



  1. Ovlivňuje pořadí tabulek v přímých spojeních bez direktiv nápovědy výkon?

  2. Omezení počtu neúspěšných pokusů o přihlášení

  3. Co je nového v MariaDB 10.4

  4. Má smysl používat MySQL LIMIT 1 při dotazování na indexované/unikátní pole?