SQL—如何跨行透视和组合数据

SQL—如何跨行透视和组合数据,sql,sql-server,postgresql,pivot,Sql,Sql Server,Postgresql,Pivot,我正在一个数据集上为一个健康应用程序模拟个人的生命体征,想象一下Fitbit。然而,对于给定的人来说,这些生命体征是作为单独的行记录和报告的。例如 TableName: PersonalVitals PersonID | RecordedTime | VitalType | VitalValue 1 | 17:10 | HR | 72bpm <- Heart rate 1 | 17:10 | R

我正在一个数据集上为一个健康应用程序模拟个人的生命体征,想象一下Fitbit。然而,对于给定的人来说,这些生命体征是作为单独的行记录和报告的。例如

TableName: PersonalVitals

PersonID | RecordedTime | VitalType | VitalValue 
   1     |    17:10     |   HR      |    72bpm       <- Heart rate
   1     |    17:10     |   RR      |    19insp/min  <- Respiratory rate
   2     |    15:35     |   RR      |    11insp/min  <- Respiratory rate
   1     |    17:15     |   HR      |    76bpm       <- Heart rate
如何在SQL(SQL server或postgres)中实现上述目标

感谢使用Pivot

SELECT PersonID , RecordedTime,[HR],[RR] ,SpO2,[BP(Blood Pressure)]
FROM
(
SELECT * ,NULL AS  SpO2,NULL AS [BP(Blood Pressure)]
FROM #PersonalVitals
)
As Src
PIVOT
(
MAX(VitalValue) FOR VitalType IN ([HR],[RR]))AS Pvt
ORDER BY PersonID

对于Postgres,我会将所有重要信息汇总为一个JSONB值,然后将其提取为列:

select person_id, 
       recorded_time, 
       vitals ->> 'HR' as "HR", 
       vitals ->> 'RR' as "RR", 
       vitals ->> 'SpO2' as "SpO2", 
       vitals ->> 'BP' as "Blood Pressure"
from (
  select person_id, recorded_time, 
         jsonb_object_agg(vital_type, vital_value) as vitals
  from person_vitals 
  group by person_id, recorded_time
) t
order by person_id, recorded_time;
在线示例:

与所有pivot解决方案一样,如果添加新的重要类型,则需要更改查询。使用上述解决方案,在外部查询中就足够了。内部查询不需要更改


如果处理该结果的代码可以处理JSON值,我只会直接返回内部查询的结果,而不是将其转换为单独的列。

您能发布到目前为止的代码吗?重要类型列表是否已修复?(您的样本数据中没有
SpO2
)这个生命体征列表是固定的,但有点大,所以我刚刚策划了上面的示例来展示几个生命体征。这个解决方案很好,但需要对生命体征的预先了解,以便可以将它们添加到外部查询的“选择”列表中。但是,如果生命体征列表未知,那么如何修改上述查询以将内部查询返回的所有生命体征列为单独的列?@sppc42:如果生命体征列表未知,则无法修改该查询以处理该问题。SQL的限制之一是,在实际执行查询之前,数据库必须知道列的数量(及其数据类型)。以“动态”方式实现这一点的唯一方法是将JSON值从内部查询返回到应用程序,并在前端处理“透视”部分(无论如何,这几乎总是更好的选择)
select person_id, 
       recorded_time, 
       vitals ->> 'HR' as "HR", 
       vitals ->> 'RR' as "RR", 
       vitals ->> 'SpO2' as "SpO2", 
       vitals ->> 'BP' as "Blood Pressure"
from (
  select person_id, recorded_time, 
         jsonb_object_agg(vital_type, vital_value) as vitals
  from person_vitals 
  group by person_id, recorded_time
) t
order by person_id, recorded_time;