以单元格名称作为列名称透视表

0 sql-server pivot

我有一个表结构是:

year | code | name| value | wef        | 
2014 | a001 | abe | 2000  | 2014-04-01 | 
2014 | a001 | def | 3000  | 2014-05-01 |
2014 | a002 | abe | 2000  | 2014-06-01 |
2014 | a003 | def | 2000  | 2014-04-01 |
2014 | a003 | mno | 5000  | 2014-06-01 |
Run Code Online (Sandbox Code Playgroud)

我需要的结果格式为:

year | code | abe | abe__wef | def | def__wef  | mno | mno____wef |   
2014 | a001 | 2000|2014-04-01|3000 | 2014-05-01|     |  
2014 | a002 | 2000|2014-06-01|     |           |     | 
2014 | a003 |     |          |2000 | 2014-04-01| 5000| 2014-06-01 
Run Code Online (Sandbox Code Playgroud)

Tar*_*ryn 5

您可以使用该PIVOT函数来获取结果,但由于您有多个要转换为列的值,因此您首先需要先查看valuewef列的逆透视。

您没有指定您使用的是哪个版本的 SQL Server,但您可以使用该UNPIVOT函数,也可以使用CROSS APPLYwithVALUESUNION ALLvalue/转换wef为多行。

语法类似于:

select year, code, col, val
from dbo.yourtable
cross apply
(
  select name, convert(varchar(10), value) union all
  select name+'_wef', convert(varchar(10), wef, 120)
) c (col, val);
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo。这会将您的数据转换为以下格式:

| YEAR | CODE |     COL |        VAL |
|------|------|---------|------------|
| 2014 | a001 |     abe |       2000 |
| 2014 | a001 | abe_wef | 2014-04-01 |
| 2014 | a001 |     def |       3000 |
| 2014 | a001 | def_wef | 2014-05-01 |
| 2014 | a002 |     abe |       2000 |
| 2014 | a002 | abe_wef | 2014-06-01 |
Run Code Online (Sandbox Code Playgroud)

现在您可以应用该PIVOT功能:

select year, code,
  abe, abe_wef, def, def_wef, mno, mno_wef
from
(
  select year, code, col, val
  from dbo.yourtable
  cross apply
  (
    select name, convert(varchar(10), value) union all
    select name+'_wef', convert(varchar(10), wef, 120)
  ) c (col, val)
) d
pivot
(
  max(val)
  for col in (abe, abe_wef, def, def_wef, mno, mno_wef)
) piv;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo

使用上述版本可能会遇到的问题是,当您的值数量有限时,它非常有效,因为您可以对查询进行硬编码。但是,如果您有未知数量的值,则该解决方案将不起作用。在您有未知数量的值的情况下,您将需要使用动态 sql 来获得最终结果:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(col) 
                    from dbo.yourtable
                    cross apply
                    (
                      select name, 1 union all
                      select name+'_wef', 2 
                    ) c (col, so)
                    group by col, so
                    order by col, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = N'SELECT year, code,' + @cols +N' 
            from 
            (
              select year, code, col, val
              from dbo.yourtable
              cross apply
              (
                select name, convert(varchar(10), value) union all
                select name+''_wef'', convert(varchar(10), wef, 120)
              ) c (col, val)
            ) x
            pivot 
            (
                max(val)
                for col in (' + @cols + N')
            ) p '

exec sp_executesql @query;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo。两个版本都会给出以下结果:

| YEAR | CODE |    ABE |    ABE_WEF |    DEF |    DEF_WEF |    MNO |    MNO_WEF |
|------|------|--------|------------|--------|------------|--------|------------|
| 2014 | a001 |   2000 | 2014-04-01 |   3000 | 2014-05-01 | (null) |     (null) |
| 2014 | a002 |   2000 | 2014-06-01 | (null) |     (null) | (null) |     (null) |
| 2014 | a003 | (null) |     (null) |   2000 | 2014-04-01 |   5000 | 2014-06-01 |
Run Code Online (Sandbox Code Playgroud)