2015-04-02 69 views
2

在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

你真的想在输出500列?这是否会有意义,即人们是否真的要阅读所有500列?通过有效地引用查询的性能,或者不必写出列,例如'(1),[2],[3],... [n])的PIVOT(最大(价值)治疗)如果只有3种治疗方案,那么应该只有3列? – GarethD 2015-04-02 16:35:27

回答

6

为了得到你想要的结果,你将不得不UNPIVOT你denomnumpct列,然后转动的treatments。要UNPIVOT,你可以使用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 | 
+0

Didn' t知道你可以使用CROSS APPLY到UNPIVOT ...显然它工作正如我从SQL小提琴中看到的那样。是否有任何理由不使用UNPIVOT?使用CROSS APPLY而不是UNPIVOT有什么好处? – 2015-04-02 20:29:48

+1

@TT。在这一点上,使用CROSS APPLY只是一种习惯,因为当你必须成对取消转换列时,它会更容易转换为unpivot。另外如果你有不同的数据类型,你可以很容易地在CROSS APPLY中转换/转换它们,而不必使用子查询,但你可以看到UNPIVOT的工作原理相同--http://sqlfiddle.com/#!6/6c614/9 – Taryn 2015-04-02 20:32:57

+0

好东西,很高兴知道 – 2015-04-02 20:36:42