SQL结合了2个表和数据透视表

时间:2015-01-30 13:31:53

标签: sql sql-server pivot

我不明白PIVOT在SQL中是如何工作的。我有2个表,我想调整其中的一个,以便只获得一个包含所有数据的表。我附上了一张图片,里面有我所拥有的桌子以及我想得到的结果。

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查询,我会非常感激。

1 个答案:

答案 0 :(得分:2)

为了获得最终结果,您将不得不实现各种方法,包括unpivot,pivot,以及使用像row_number()这样的窗口函数。

由于Table2中有多个需要轮换的列,因此您需要先将它们取消。这与pivot相反,它将您的多列转换为多行。但是在你移开之前,你需要一些价值来使用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。创建此唯一标识符后,您将unpivot L_valuelrmslatTmaxrdc。您可以使用几种不同的方法来取消数据,包括unpivot函数,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;

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