4

我将 Microsoft SQL Server 2008 用于心理健康组织。

我有一张表格,列出了所有客户及其诊断,但客户的每个诊断都在一个新行中。我希望它们都排在一行中,并与每个诊断的日期一起水平列出。有些人只有一个诊断,有些人有 20 个,有些人没有。

这是我的数据现在看起来如何的示例(只有少数客户,我们有数千个): http://i.imgur.com/pBV4svz.png

这是我希望它结束​​的格式: http://i.imgur.com/8cM2iNa.png

您可以提供的任何解决方案或正确方向的提示都会很棒,谢谢!

4

4 回答 4

5

为了获得结果,我将首先取消透视然后透视您的数据。unpivot将获取您的日期和诊断列并将它们转换为行。一旦数据成行,您就可以应用数据透视。

如果您有已知数量的值,则可以对查询进行硬编码,如下所示:

select *
from
(
  select person, [case#], age,
    col+'_'+cast(rn as varchar(10)) col,
    value
  from
  (
    select person, 
      [case#],
      age,
      diagnosis,
      convert(varchar(10), diagnosisdate, 101) diagnosisDate,
      row_number() over(partition by person, [case#]
                        order by DiagnosisDate) rn
    from yourtable
  ) d
  cross apply
  (
    values ('diagnosis', diagnosis), ('diagnosisDate', diagnosisDate)
  ) c (col, value)
) t
pivot
(
  max(value)
  for col in (diagnosis_1, diagnosisDate_1,
              diagnosis_2, diagnosisDate_2,
              diagnosis_3, diagnosisDate_3,
              diagnosis_4, diagnosisDate_4)

) piv;

请参阅SQL Fiddle with Demo

我将假设您对每个病例​​都有未知数量的诊断值。如果是这种情况,那么您将需要使用动态 sql 来生成结果:

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

select @cols = STUFF((SELECT  ',' + QUOTENAME(col+'_'+cast(rn as varchar(10))) 
                    from 
                    (
                      select row_number() over(partition by person, [case#]
                                                order by DiagnosisDate) rn
                      from yourtable
                    ) t
                    cross join 
                    (
                      select 'Diagnosis' col union all 
                      select 'DiagnosisDate'
                    ) c
                    group by col, rn
                    order by rn, col
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT person, 
                    [case#],
                    age,' + @cols + '  
             from
             (
                select person, [case#], age,
                  col+''_''+cast(rn as varchar(10)) col,
                  value
                from
                (
                  select person, 
                    [case#],
                    age,
                    diagnosis,
                    convert(varchar(10), diagnosisdate, 101) diagnosisDate,
                    row_number() over(partition by person, [case#]
                                      order by DiagnosisDate) rn
                  from yourtable
                ) d
                cross apply
                (
                  values (''diagnosis'', diagnosis), (''diagnosisDate'', diagnosisDate)
                ) c (col, value)
            ) t
            pivot 
            (
                max(value)
                for col in (' + @cols + ')
            ) p '

execute(@query);

请参阅SQL Fiddle with Demo。两个查询都给出了结果:

| PERSON |  CASE# | AGE |   DIAGNOSIS_1 | DIAGNOSISDATE_1 |      DIAGNOSIS_2 | DIAGNOSISDATE_2 |        DIAGNOSIS_3 | DIAGNOSISDATE_3 |  DIAGNOSIS_4 | DIAGNOSISDATE_4 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   John |  13784 |  56 |    Depression |      03/13/2012 |     Brain Injury |      03/14/2012 | Spinal Cord Injury |      03/15/2012 | Hypertension |      03/16/2012 |
|   Kate |   2643 |  37 |       Bipolar |      03/11/2012 |     Hypertension |      03/12/2012 |             (null) |          (null) |       (null) |          (null) |
|  Kevin | 500934 |  25 | Down Syndrome |      03/18/2012 | Clinical Obesity |      03/19/2012 |             (null) |          (null) |       (null) |          (null) |
|   Pete | 803342 |  34 |  Schizophenia |      03/17/2012 |           (null) |          (null) |             (null) |          (null) |       (null) |          (null) |
于 2013-04-04T16:13:37.500 回答
1

对于这种类型的旋转,我认为聚合/分组方法是可行的:

select d.case, d.person,
       max(case when seqnum = 1 then diagnosis end) as d1,
       max(case when seqnum = 1 then diagnosisdate end) as d1date,
       max(case when seqnum = 2 then diagnosis end) as d2,
       max(case when seqnum = 2 then diagnosisdate end) as d2date,
       . . . -- and so on, for as many groups that you want
from (select d.*, row_number() over (partition by case order by diagnosisdate) as seqnum
      from diagnoses d
     ) d
group by d.case, d.person
于 2013-04-04T16:09:40.433 回答
0

由于您正在处理敏感的医疗信息,因此不应将可识别信息(姓名年龄等)存储在与医疗信息相同的表中。此外,如果您将人员信息提取到其自己的表和具有 personID 外键的诊断表中,您可以建立所需的一对多关系。

于 2013-04-04T16:04:46.283 回答
0

除非您使用动态 SQL,否则 PIVOT 运算符将无法在这里工作。我认为病人可以在任何日期进来。PIVOT 运算符使用有限且预定义的列数。您的选择是使用动态 SQL 来创建 PIVOT 表,或者使用 Excel 或 SSRS 等报告工具来生成数据透视报告。

我认为动态 SQL 选项在这里不实用,因为对于每个患者就诊日期,您最终可能会有数百列。

如果您仍然想探索动态 SQL 选项,请查看此处:

https://www.simple-talk.com/blogs/2007/09/14/pivots-with-dynamic-columns-in-sql-server-2005/

于 2013-04-04T16:13:50.477 回答