我将 Microsoft SQL Server 2008 用于心理健康组织。
我有一张表格,列出了所有客户及其诊断,但客户的每个诊断都在一个新行中。我希望它们都排在一行中,并与每个诊断的日期一起水平列出。有些人只有一个诊断,有些人有 20 个,有些人没有。
这是我的数据现在看起来如何的示例(只有少数客户,我们有数千个):
这是我希望它结束的格式:
您可以提供的任何解决方案或正确方向的提示都会很棒,谢谢!
我将 Microsoft SQL Server 2008 用于心理健康组织。
我有一张表格,列出了所有客户及其诊断,但客户的每个诊断都在一个新行中。我希望它们都排在一行中,并与每个诊断的日期一起水平列出。有些人只有一个诊断,有些人有 20 个,有些人没有。
这是我的数据现在看起来如何的示例(只有少数客户,我们有数千个):
这是我希望它结束的格式:
您可以提供的任何解决方案或正确方向的提示都会很棒,谢谢!
为了获得结果,我将首先取消透视然后透视您的数据。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 来生成结果:
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) |
对于这种类型的旋转,我认为聚合/分组方法是可行的:
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
由于您正在处理敏感的医疗信息,因此不应将可识别信息(姓名年龄等)存储在与医疗信息相同的表中。此外,如果您将人员信息提取到其自己的表和具有 personID 外键的诊断表中,您可以建立所需的一对多关系。
除非您使用动态 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/