根据表列动态合并两列或更多列?

时间:2013-03-14 16:08:22

标签: sql sql-server pivot

我有一个名为SectionNames的表,如下所示

SectionID   SectionCode     Subsection
   1            xYz         Individual
   2            xYz         Family
   3            CYD         Friends
   4            PCPO        level1
   5            PCPO        level2
   6            PCPO        level3

等等。因此,将来我们可以为每个部分代码添加一个或多个子部分。

还有一个表,它是上述SectionNames表和Employee表的参考表,包含员工数据。

ID    EmployeeID    SectionID   Cost    
1           1              1    $200
2           1              2    $300    
3           1              3    $40 
4           1              4    $10 
5           1              5    No Level
6           1              6    No Level
7           1              7    $20 
8           1              8    No Level
9           1              9    No Level

所以我希望这些表中的输出看起来像:

EmployeeID     Individual_xyz_Cost    Family_xyz_Cost    Friends_xyz_cost  level1_PCPO_cost  level2_PCPO_Cost
   1                 $200                 $300               $400              $10             NoLevel

我的员工表中存在很少的员工记录。我希望这是动态的。如果将来如果为Relatives部分添加了一个名为XYZ的子部分,则我的查询应返回Relatives_XYZ_Cost

如何动态编写此查询?

1 个答案:

答案 0 :(得分:6)

您需要使用PIVOT函数将数据从列转换为行。如果您将需要未知数量的值作为列,那么您将需要使用动态SQL。

首先看到静态或硬编码版本然后将其转换为动态SQL版本会更容易。如果您具有已知数量的值,则使用静态版本:

select *
from
(
  select e.employeeid,
    s.subsection +'_'+s.sectioncode+'_Cost' Section,
    e.cost
  from employee e
  inner join sectionnames s
    on e.sectionid = s.sectionid
) src
pivot
(
  max(cost)
  for section in (Individual_xYz_Cost, Family_xYz_Cost,
                  Friends_CYD_Cost, level1_PCPO_Cost,
                  level2_PCPO_Cost, level3_PCPO_Cost)
) piv;

请参阅SQL Fiddle with Demo

如果您需要灵活的查询,那么您将转换为使用动态SQL:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(subsection +'_'+sectioncode+'_Cost') 
                    from SectionNames
                    group by subsection, sectioncode, sectionid
                    order by sectionid
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT employeeid,' + @cols + ' 
              from 
             (
                select e.employeeid,
                  s.subsection +''_''+s.sectioncode+''_Cost'' Section,
                  e.cost
                from employee e
                inner join sectionnames s
                  on e.sectionid = s.sectionid
            ) x
            pivot 
            (
                max(cost)
                for section in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

两者的结果是:

| EMPLOYEEID | INDIVIDUAL_XYZ_COST | FAMILY_XYZ_COST | FRIENDS_CYD_COST | LEVEL1_PCPO_COST | LEVEL2_PCPO_COST | LEVEL3_PCPO_COST |
----------------------------------------------------------------------------------------------------------------------------------
|          1 |                $200 |            $300 |              $40 |              $10 |         No Level |         No Level |