在mysql中给出一个名为RECORD的表,结构如下:
rid(pk & AI) patientid(fk) recordTYPE(varchar) recordValue(varchar) recordTimestamp(timestamp)
1 1 temperature(℃) 37.2 2015-08-11 18:10:04
2 1 weight(kg) 65.0 2015-08-11 18:20:08
3 1 heartbeat(bpm) 66 2015-08-11 18:30:08
4 1 temperature(℃) 36.8 2015-08-11 18:32:08
您可以看到,对于同一日期,一种特定类型的记录可能有多条记录。例如样本数据中的温度:
rid patientid recordTYPE value recordtimestamp
1 1 temperature(℃) 37.2 2015-08-11 18:10:04
4 1 temperature(℃) 36.8 2015-08-11 18:32:08
在这种情况下,我们应该选择最新的记录。即,rid = 4且值= 36.8的记录。
现在给出输入日期,例如'2015-8-11',我想做一个查询来获得类似的东西:
date patientid temperature(℃) weight(kg) heartbeat(bpm)
2015-08-11 1 36.8 65.0 66
2015-08-11 2 36.5 80.3 70
2015-08-11 3 35.5 90.5 80
..........................................................
..........................................................
2015-08-11 4 35.5 null null
Fig. 2
此外,您可以看到,对于特定日期,可能没有某些类型的记录。在这种情况下,该列中的值为null。
我尝试了以下查询:
SELECT max(recordTimestamp), patientid, recordTYPE, recordValue
FROM RECORD
WHERE date(recordTimestamp) = '2015-08-11'
GROUP BY patientid, recordTYPE
结果如下:
date patientid recordTYPE recordValue
2015-08-11 1 temperature(℃) 36.8
2015-08-11 1 weight(kg) 65.0
2015-08-11 1 heartbeat(bpm) 66
2015-08-11 2 temperature(℃) 36.5
2015-08-11 2 weight(kg) 80.3
2015-08-11 2 heartbeat(bpm) 70
2015-08-11 4 temperature(℃) 35.5
Fig. 4
问题是:
鉴于此表RECORD,正确的mysql语句是什么(用术语表示 如检索速度等性能,以产生所需的结果集(即图2)?
- 醇>
如果更改数据库设计,是否会更好(在促进查询和可扩展性方面,例如添加新类型的记录)? 例如为每种记录类型创建一个表,而不是将所有类型的记录放在一个表中。
任何建议都表示赞赏,因为我是db新手......谢谢。
答案 0 :(得分:0)
你可以试试这个: -
SELECT MAX(rid), patientid, recordTYPE, MAX(recordValue), recordTimestamp
FROM YOUR_TABLE
WHERE recordTimestamp = '2015/08/11'
GROUP BY patientid, recordTYPE, recordTimestamp;
答案 1 :(得分:0)
这是一种方法。 SQL Fiddle Demo
遗憾的是,MySQL并不支持row_number() over (partition by ...)
语法,这会大大简化这一点。
相反,我已经过度使用了这里讨论的技巧:https://stackoverflow.com/a/3470355/361842
select `date`
, `patientId`
, max(case when `tRank`=1 then `temperature(℃)` else null end) `temperature(℃)`
, max(case when `wRank`=1 then `weight(kg)` else null end) `weight(kg)`
, max(case when `hRank`=1 then `heartbeat(bpm)` else null end) `heartbeat(bpm)`
from
(
select case when @p = `patientId` and @d = cast(`recordTimestamp` as date) then @x := 1 else @x := 0 end
, case when @x = 0 then @t := 0 end
, case when @x = 0 then @w := 0 end
, case when @x = 0 then @h := 0 end
, case `recordType` when 'temperature(℃)' then case @x when 1 then @t := @t + 1 else @t := 1 end else null end as `tRank`
, case `recordType` when 'weight(kg)' then case @x when 1 then @w := @w + 1 else @t := 1 end else null end as `wRank`
, case `recordType` when 'heartbeat(bpm)' then case @x when 1 then @h := @h + 1 else @t := 1 end else null end as `hRank`
, case `recordType` when 'temperature(℃)' then `recordValue` else null end as `temperature(℃)`
, case `recordType` when 'weight(kg)' then `recordValue` else null end as `weight(kg)`
, case `recordType` when 'heartbeat(bpm)' then `recordValue` else null end as `heartbeat(bpm)`
, @d := cast(`recordTimestamp` as date) as `date`
, @p := `patientId` as `patientId`
from `Record`
cross join
(
SELECT @t := 0
, @w := 0
, @h := 0
, @p := 0
, @x := 0
, @d := cast(null as date)
) x
order by `patientId`, `recordTimestamp` desc
) y
group by `date`, `patientId`
order by `date`, `patientId`
<强>击穿强>
这表示如果这是当前分组的partientId / date组合的当天的最后一个温度,则返回它;否则返回null。然后它取最大的匹配值(给出除1之外的所有值都为空,给出我们之后的那个)。
, max(case when `tRank`=1 then `temperature(℃)` else null end)
tRank = 1
如何表示患者日/日期组合当天的最后一个温度将在稍后解释。
此行表示如果此记录与上一记录具有相同的patientId和日期,则将x
设置为1;如果是新组合,则将其设置为0。
select case when @p = `patientId` and @d = cast(`recordTimestamp` as date) then @x := 1 else @x := 0 end
下一行说明如果我们有新的patiendIt / date组合,请重置t
,w
和h
标记以说明&#34;您收到的下一个值将是是我们之后的那个&#34;。
, case when @x = 0 then @t := 0 end
接下来的行按recordType分割数据;如果此记录不是他们的记录类型,则返回null,或者返回一个数字,说明我们现在为patientId / date组合记录了多少此类记录。
, case `recordType` when 'temperature(℃)' then case @x when 1 then @t := @t + 1 else @t := 1 end else null end as `tRank`
这与上述类似;除了返回组合计数器之外,它返回当前记录的值(如果这是不同的记录类型,则返回null)。
, case `recordType` when 'temperature(℃)' then `recordValue` else null end as `temperature(℃)`
然后我们记录当前记录的日期和patientId值,这样我们就可以将它们与下一次迭代的下一条记录进行比较。
, @d := cast(`recordTimestamp` as date) as `date`
, @p := `patientId` as `patientId`
cross join
及以下子查询仅用于初始化变量。
(第一个)order by
用于确保比较当前和之前的记录足以判断我们是否正在查看不同的组合(即,如果所有组合都已分组,那么任何更改都很容易发现;如果组合保持交替,我们需要跟踪我们之前看到的每个组合)。
recordTimestamp
按降序排序,以便我们在新组合中看到的第一条记录将是当天的最后一条记录;我们追求的那个。
group by
用于确保每个组合获得1个结果;和最后order by
只是为了使我们的输出有序。