2015-01-30 2 views
2

Я не понимаю, как PIVOT работает в SQL. У меня есть 2 таблицы, и я хотел бы выделить 1 из них, чтобы получить только 1 таблицу со всеми данными вместе. Я прикрепил изображение с таблицами, которые у меня есть, и результат, который я хотел бы получить.SQL comb 2 table and pivot

enter image description here

CREATE TABLE TABLE1 
    ([serie_id] varchar(4), [Maturity] int, [Strategy] int, [Lifetime] varchar(4), [L_max] decimal(10, 5), [W_max] decimal(10, 5), [H_max] decimal(10, 5)) 
; 

INSERT INTO TABLE1 
    ([serie_id], [Maturity], [Strategy], [Lifetime], [L_max], [W_max], [H_max]) 
VALUES 
    ('id_1', 3, 1, '2', 2.200, 1.400, 1.400), 
    ('id_2', 3, 1, '2', 3.400, 1.800, 2.100), 
    ('id_3', 3, 1, NULL, 24.500, 14.500, 15.000), 
    ('id_4', 3, 1, NULL, 28.000, 24.500, 14.000) 
; 

CREATE TABLE TABLE2 
    ([serie_id] varchar(4), [L_value] decimal(10, 5), [lrms] decimal(10, 5), [latTmax] decimal(10, 5), [Rdc] decimal(10, 5)) 
; 

INSERT INTO TABLE2 
    ([serie_id], [L_value], [lrms], [latTmax], [Rdc]) 
VALUES 
    ('id_1', 67.000, 400.000, 400.000, 0.250), 
    ('id_1', 90.000, 330.000, 330.000, 0.350), 
    ('id_1', 120.000, 370.000, 370.000, 0.300), 
    ('id_1', 180.000, 330.000, 300.000, 0.350), 
    ('id_2', 260.000, 300.000, 300.000, 0.400), 
    ('id_2', 360.000, 280.000, 280.000, 0.450), 
    ('id_3', 90.000, 370.000, 370.000, 0.300), 
    ('id_4', 160.000, 340.000, 340.000, 0.400) 
; 

SQLFiddle

Если кто-то может помочь мне с запросом SQL я оценил бы его так много.

+0

вместо изображений размещать выборочные данные с sqlfiddle –

+0

проблема заключается в том, что я не знаю как получить таблицу «Результат», чтобы сделать ее в sqlfiddle ... по этой причине я подумал, что проще было – Mastor

+2

@ user2528601 проще для вас, может быть ...сложнее ** всех **, которые могут потенциально вам помочь: P – Kritner

ответ

2

Для того, чтобы получить окончательный результат, вам нужно будет реализовать множество методов, включая univot, pivot, а также использовать функцию оконной обработки, такую ​​как row_number().

Поскольку у вас есть несколько столбцов в Table2, которые должны быть повернуты, вам сначала нужно отключить их. Это противоположность оси, которая преобразует несколько столбцов в несколько строк. Но перед тем, как вы откажетесь, вам нужно какое-то значение, чтобы определить значения каждой строки, используя row_number() - звучит сложно, не так ли?

Во-первых, запрос table2 с использованием оконной функции row_number(). Это создает уникальный идентификатор для каждой строки и позволяет вам легко сопоставлять значения для id_1 от любого другого.

select serie_id, l_value, lrms, latTmax, Rdc, 
    rn = cast(row_number() over(partition by serie_id order by serie_id) 
       as varchar(10)) 
from table2; 

См. Demo. После того, как вы создали этот уникальный идентификатор, вы получите unpivotL_value, lrms, latTmax и rdc. Вы можете отключить данные, используя несколько разных методов, включая функцию univot, CROSS APPLY или UNION ALL.

select serie_id, 
    col, value 
from 
(
    select serie_id, l_value, lrms, latTmax, Rdc, 
    rn = cast(row_number() over(partition by serie_id order by serie_id) 
       as varchar(10)) 
    from table2 
) d 
cross apply 
(
    select 'L_value_'+rn, L_value union all 
    select 'lrms_'+rn, lrms union all 
    select 'latTmax_'+rn, latTmax union all 
    select 'Rdc_'+rn, Rdc 
) c (col, value) 

См. SQL Fiddle with Demo. Данные table2 не находится в совершенно другом формате, который может быть повернута в новые столбцы:

| SERIE_ID |  COL | VALUE | 
|----------|-----------|-------| 
|  id_1 | L_value_1 | 67 | 
|  id_1 | lrms_1 | 400 | 
|  id_1 | latTmax_1 | 400 | 
|  id_1 |  Rdc_1 | 0.25 | 
|  id_1 | L_value_2 | 90 | 
|  id_1 | lrms_2 | 330 | 
|  id_1 | latTmax_2 | 330 | 
|  id_1 |  Rdc_2 | 0.35 | 

Заключительный шаг должен был бы откинуть данные выше в конечный результат:

select serie_id, maturity, strategy, lifetime, l_max, w_max, h_max, 
    L_value_1, lrms_1, latTmax_1, Rdc_1, 
    L_value_2, lrms_2, latTmax_2, Rdc_2, 
    L_value_3, lrms_3, latTmax_3, Rdc_3, 
    L_value_4, lrms_4, latTmax_4, Rdc_4 
from 
(
    select t1.serie_id, t1.maturity, t1.strategy, t1.lifetime, 
    t1.l_max, t1.w_max, t1.h_max, 
    t2.col, t2.value 
    from table1 t1 
    inner join 
    (
    select serie_id, 
     col, value 
    from 
    (
     select serie_id, l_value, lrms, latTmax, Rdc, 
     rn = cast(row_number() over(partition by serie_id order by serie_id) 
        as varchar(10)) 
     from table2 
    ) d 
    cross apply 
    (
     select 'L_value_'+rn, L_value union all 
     select 'lrms_'+rn, lrms union all 
     select 'latTmax_'+rn, latTmax union all 
     select 'Rdc_'+rn, Rdc 
    ) c (col, value) 
) t2 
    on t1.serie_id = t2.serie_id 
) d 
pivot 
(
    max(value) 
    for col in (L_value_1, lrms_1, latTmax_1, Rdc_1, 
       L_value_2, lrms_2, latTmax_2, Rdc_2, 
       L_value_3, lrms_3, latTmax_3, Rdc_3, 
       L_value_4, lrms_4, latTmax_4, Rdc_4) 
) p; 

See SQL Fiddle with Demo.

Если у вас есть неизвестное количество значений в Table2, вам нужно будет использовать динамический SQL для создания строки sql, которая будет выполнена. Преобразование вышеуказанного кода в динамический sql довольно легко, как только вы правильно определили логику. Код будет:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols 
    = STUFF((SELECT ',' + QUOTENAME(col+cast(rn as varchar(10))) 
      from 
      (
       select rn = cast(row_number() over(partition by serie_id order by serie_id) 
        as varchar(10)) 
       from table2 
      ) d 
      cross apply 
      (
       select 'L_value_', 0 union all 
       select 'lrms_', 1 union all 
       select 'latTmax_', 2 union all 
       select 'Rdc_', 3 
      ) c (col, so) 
      group by col, rn, so 
      order by rn, so 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 


set @query = N'SELECT serie_id, maturity, strategy, lifetime, l_max, 
       w_max, h_max,' + @cols + N' 
       from 
      (
       select t1.serie_id, t1.maturity, t1.strategy, t1.lifetime, 
       t1.l_max, t1.w_max, t1.h_max, 
       t2.col, t2.value 
       from table1 t1 
       inner join 
       (
       select serie_id, 
        col, value 
       from 
       (
        select serie_id, l_value, lrms, latTmax, Rdc, 
        rn = cast(row_number() over(partition by serie_id order by serie_id) 
           as varchar(10)) 
        from table2 
       ) d 
       cross apply 
       (
        select ''L_value_''+rn, L_value union all 
        select ''lrms_''+rn, lrms union all 
        select ''latTmax_''+rn, latTmax union all 
        select ''Rdc_''+rn, Rdc 
       ) c (col, value) 
      ) t2 
       on t1.serie_id = t2.serie_id 
      ) x 
      pivot 
      (
       max(value) 
       for col in (' + @cols + N') 
      ) p ' 

exec sp_executesql @query 

См SQL Fiddle with Demo

Обе версии будут давать результат:

| SERIE_ID | MATURITY | STRATEGY | LIFETIME | L_MAX | W_MAX | H_MAX | L_VALUE_1 | LRMS_1 | LATTMAX_1 | RDC_1 | L_VALUE_2 | LRMS_2 | LATTMAX_2 | RDC_2 | L_VALUE_3 | LRMS_3 | LATTMAX_3 | RDC_3 | L_VALUE_4 | LRMS_4 | LATTMAX_4 | RDC_4 | 
|----------|----------|----------|----------|-------|-------|-------|-----------|--------|-----------|-------|-----------|--------|-----------|--------|-----------|--------|-----------|--------|-----------|--------|-----------|--------| 
|  id_1 |  3 |  1 |  2 | 2.2 | 1.4 | 1.4 |  67 | 400 |  400 | 0.25 |  90 | 330 |  330 | 0.35 |  120 | 370 |  370 | 0.3 |  180 | 330 |  300 | 0.35 | 
|  id_2 |  3 |  1 |  2 | 3.4 | 1.8 | 2.1 |  260 | 300 |  300 | 0.4 |  360 | 280 |  280 | 0.45 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | 
|  id_3 |  3 |  1 | (null) | 24.5 | 14.5 | 15 |  90 | 370 |  370 | 0.3 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | 
|  id_4 |  3 |  1 | (null) | 28 | 24.5 | 14 |  160 | 340 |  340 | 0.4 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |