关于多个字段问题的SQLServer 2008 PIVOT

时间:2014-02-14 17:56:20

标签: sql sql-server-2008-r2 pivot unpivot

我正在尝试在3个字段/列上使用PIVOT,即站点,值,日期。我正在使用SQLServer 2008.请检查下面我的实际表和所需的输出表以及我使用的数据透视查询

实际表格:

**tblReference**


**ID**            **Refer_code**    **Site**    **Value**   **Date**

  1                 9290             CA            12.5         2014-01-01 20:20:41

  5                 9290             TX            12.6         2014-01-05 18:20:30

  2                 6651             CA            13.5         2014-01-01 21:20:21

  3                 7442             TX            14.5         2014-01-05 19:15:14

  4                 8093             CA            15.5         2014-01-01 19:20:20

  6                 8093             TX            16.5         2014-01-05 20:20:20


**Desired output table:**


**Refer_code**   **Site_1** **Site_2**  **Val_1**  **Val_2**    **StartDate**   **EndDate**

   9290            CA         TX      12.5       12.6   2014-01-01      2014-01-05
                                                                20:20:41    18:20:30

   6651            CA         NULL    13.5       NULL   2014-01-01      NULL
                                                                21:20:21    

   7442            NULL       TX      NULL       14.5   NULL            2014-01-05 
                                                                                19:15:14

   8093            CA         TX      15.5       16.5   2014-01-01      2014-01-05
                                                                19:20:20    20:20:20


 **Query:**

        SELECT Refer_code, [Site_1], [Site_2], [Date_1] AS StartDate, [Date_2] AS EndDate, [Val_1], [Val_2]
        FROM
        (
        SELECT Refer_code, Site, 'Site_'+ cast(row_number() over(partition by Refer_code order by Date) as nvarchar(50)) SiteVal,Date,'Date_'+cast(row_number() over(partition by Refer_code order by Date) as nvarchar(50)) DateVal,Value,'Val_'+cast(row_number() over(partition by Refer_code order by Date) as nvarchar(50)) Val
            FROM tblReference
        ) x
        pivot 
        (
            min(Site)
            for SiteVal in ([Site_1], [Site_2])
        ) p 
        pivot
        (
            min(Date)
            for DateVal in ([Date_1], [Date_2])
        ) s
        pivot
        (
            min(Value)
            for Val in ([Val_1], [Val_2])
        ) t

上述查询未按预期返回结果。请帮我解决。

1 个答案:

答案 0 :(得分:2)

有几种方法可以获得所需的结果。最简单的方法可能是使用带有CASE表达式的聚合函数,但您也可以使用PIVOT函数。

与CASE聚合:

我会采取以下步骤,首先使用refer_code为每个row_number()创建一个唯一的序列:

select refer_code, site, 
  row_number() over(partition by refer_code
                    order by date) seq,
  value,
  date
from tblReference;

SQL Fiddle with Demo

拥有唯一序列后,您可以通过应用带有CASE表达式的聚合函数轻松将现有数据转换为多个列:

;with cte as
(
  select refer_code, site, 
    row_number() over(partition by refer_code
                      order by date) seq,
    value,
    date
  from tblReference
)
select refer_code,
  max(case when seq = 1 then site end) site1,
  max(case when seq = 2 then site end) site2,
  max(case when seq = 1 then value end) value1,
  max(case when seq = 2 then value end) value2,
  max(case when seq = 1 then date end) startdate,
  max(case when seq = 2 then date end) enddate
from cte
group by refer_code;

请参阅SQL Fiddle with Demo

<强> PIVOT:

如果你想使用PIVOT功能,你需要转动多个列,我建议先看看这些列的转换,然后应用pivot功能。您需要创建用于新列名称的唯一序列,然后您需要取消忽略sitedatevalue列。由于您使用的是SQL Server 2008+,因此可以CROSS APPLY使用VALUEs将多列拆分为多行:

;with cte as
(
  select refer_code, site, 
    row_number() over(partition by refer_code
                      order by date) seq,
    value,
    date
  from tblReference
)
select *
from
(
  select refer_code, 
    col = col + cast(seq as varchar(10)),
    val
  from cte
  cross apply
  (
    values
      ('Site', site),
      ('Value', cast(value as varchar(10))),
      ('Date', convert(varchar(10), date, 120))
  ) c (col, val)
) d;

SQL Fiddle with Demo。这会使您的数据格式为:

| REFER_CODE |    COL |        VAL |
|------------|--------|------------|
|       6651 |  Site1 |         CA |
|       6651 | Value1 |      13.50 |
|       6651 |  Date1 | 2014-01-01 |
|       7442 |  Site1 |         TX |
|       7442 | Value1 |      14.50 |
|       7442 |  Date1 | 2014-01-05 |

现在您可以轻松应用pivot函数来获得最终结果,因此整个代码将是:

;with cte as
(
  select refer_code, site, 
    row_number() over(partition by refer_code
                      order by date) seq,
    value,
    date
  from tblReference
)
select refer_code, 
  site1, site2, 
  startdate = date1, enddate = date2,
  value1, value2
from
(
  select refer_code, 
    col = col + cast(seq as varchar(10)),
    val
  from cte
  cross apply
  (
    values
      ('Site', site),
      ('Value', cast(value as varchar(10))),
      ('Date', convert(varchar(10), date, 120))
  ) c (col, val)
) d
pivot
(
  max(val)
  for col in (site1, site2, date1, date2,
              value1, value2)
) piv;

SQL Fiddle with Demo。两者都会给出结果:

| REFER_CODE | SITE1 |  SITE2 |  STARTDATE |    ENDDATE | VALUE1 | VALUE2 |
|------------|-------|--------|------------|------------|--------|--------|
|       6651 |    CA | (null) | 2014-01-01 |     (null) |  13.50 | (null) |
|       7442 |    TX | (null) | 2014-01-05 |     (null) |  14.50 | (null) |
|       8093 |    CA |     TX | 2014-01-01 | 2014-01-05 |  15.50 |  16.50 |
|       9290 |    CA |     TX | 2014-01-01 | 2014-01-05 |  12.50 |  12.60 |

编辑:

根据您的评论,您需要将列CA设置为site1等,然后获得结果的最简单方法是使用带CASe的聚合函数:

select refer_code,
  max(case when site = 'CA' then site end) site1,
  max(case when site = 'TX' then site end) site2,
  max(case when site = 'CA' then value end) value1,
  max(case when site = 'TX' then value end) value2,
  max(case when site = 'CA' then date end) startdate,
  max(case when site = 'TX' then date end) endate
from tblReference
group by refer_code;

SQL Fiddle with Demo。这给出了一个结果:

| REFER_CODE |  SITE1 |  SITE2 | VALUE1 | VALUE2 |                      STARTDATE |                         ENDATE |
|------------|--------|--------|--------|--------|--------------------------------|--------------------------------|
|       6651 |     CA | (null) |   13.5 | (null) | January, 01 2014 21:20:21+0000 |                         (null) |
|       7442 | (null) |     TX | (null) |   14.5 |                         (null) | January, 05 2014 19:15:14+0000 |
|       8093 |     CA |     TX |   15.5 |   16.5 | January, 01 2014 19:20:20+0000 | January, 05 2014 20:20:20+0000 |
|       9290 |     CA |     TX |   12.5 |   12.6 | January, 01 2014 20:20:41+0000 | January, 05 2014 18:20:30+0000 |