我该怎么做Pivot(转置)

时间:2015-04-02 16:24:30

标签: sql sql-server pivot

在SQL-Server中工作,我有下表:

    visit    temperature    treatment    denom    num    pct
    A        <38°C          1            101      98     97.0
    A        38.0-38.4°C    1            103      2      1.9
    A        38.5-38.9°C    1            100      1      1.0
    A        <38°C          2            100      97     97.0
    A        38.0-38.4°C    2            100      1      1.0
    A        38.5-38.9°C    2            102      4      3.9
    B        <38°C          1            101      89     88.1
    B        38.0-38.4°C    1            100      2      2.0
    B        38.5-38.9°C    1            105      1      1.0
    B        <38°C          2            104      96     96.4
    B        38.0-38.4°C    2            104      5      1.8
    B        38.5-38.9°C    2            100      3      3.0

如何使表格看起来像这样?:

    visit    temperature    name         _1       _2
    A        <38°C          denom        101.0    100.0
    A        <38°C          num          98.0     97.0
    A        <38°C          pct          97.0     97.0
    A        38.0-38.4°C    denom        103.0    100.0
    A        38.0-38.4°C    num          2.0      1.0
    A        38.0-38.4°C    pct          1.9      1.0
    A        38.5-38.9°C    denom        100.0    102.0
    A        38.5-38.9°C    num          1.0      4.0
    A        38.5-38.9°C    pct          1.0      3.9
    B        <38°C          denom        101.0    104.0
    B        <38°C          num          89.0     96.0
    B        <38°C          pct          88.1     96.4
    B        38.0-38.4°C    denom        100.0    104.0
    B        38.0-38.4°C    num          2.0      5.0
    B        38.0-38.4°C    pct          2.0      1.8
    B        38.5-38.9°C    denom        105.0    100.0
    B        38.5-38.9°C    num          1.0      3.0
    B        38.5-38.9°C    pct          1.0      3.0

其中数字列中的_n是治疗出现的,对于某些访问可能有500次治疗,如何有效地处理,而不必将_1作为第一个旋转列,_2作为第二个旋转列,... ,_n作为最后一个旋转列?

由于

1 个答案:

答案 0 :(得分:6)

为了获得您想要的结果,您将不得不取消忽略denomnumpct列,然后转动treatments。要取消显示列,您可以使用CROSS APPLY甚至UNPIVOT - 这会将这些多列转换为多行:

select t.visit, t.temperature, t.treatment,
  name,
  val
from yourtable t
cross apply
(
  select 'denom', denom union all
  select 'num', num union all
  select 'pct', pct
) c (name, val)

Demo。然后你应用PIVOT:

select visit, temperature, name, [1], [2]
from 
(
  select t.visit, t.temperature, t.treatment,
    name,
    val
  from yourtable t
  cross apply
  (
    select 'denom', denom union all
    select 'num', num union all
    select 'pct', pct
  ) c (name, val)
) d
pivot
(
  max(val)
  for treatment in ([1], [2])
)piv;

SQL Fiddle with Demo。现在上面的代码要求你写出所有的treatment,如果你有一个未知的数字,那么你需要使用动态SQL。动态SQL创建一个然后执行的字符串:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(treatment) 
                    from yourtable
                    group by treatment
                    order by treatment
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT visit, temperature, name,' + @cols + ' 
            from 
             (
                select t.visit, t.temperature, t.treatment,
                  name,
                  val
                from yourtable t
                cross apply
                (
                  select ''denom'', denom union all
                  select ''num'', num union all
                  select ''pct'', pct
                ) c (name, val)
            ) x
            pivot 
            (
                max(val)
                for treatment in (' + @cols + ')
            ) p '

exec sp_executesql @query;

SQL Fiddle with Demo。这些都给出了:

| visit | temperature |  name |    1 |    2 |
|-------|-------------|-------|------|------|
|     A |       <38°C | denom |  101 |  100 |
|     A |       <38°C |   num |   98 |   97 |
|     A |       <38°C |   pct |   97 |   97 |
|     A | 38.0-38.4°C | denom |  103 |  100 |
|     A | 38.0-38.4°C |   num |    2 |    1 |
|     A | 38.0-38.4°C |   pct |  1.9 |    1 |
|     A | 38.5-38.9°C | denom |  100 |  102 |
|     A | 38.5-38.9°C |   num |    1 |    4 |
|     A | 38.5-38.9°C |   pct |    1 |  3.9 |
|     B |       <38°C | denom |  101 |  104 |
|     B |       <38°C |   num |   89 |   96 |
|     B |       <38°C |   pct | 88.1 | 96.4 |
|     B | 38.0-38.4°C | denom |  100 |  104 |
|     B | 38.0-38.4°C |   num |    2 |    5 |
|     B | 38.0-38.4°C |   pct |    2 |  1.8 |
|     B | 38.5-38.9°C | denom |  105 |  100 |
|     B | 38.5-38.9°C |   num |    1 |    3 |
|     B | 38.5-38.9°C |   pct |    1 |    3 |