【问题标题】:Select rows for last n days after event occurs选择事件发生后最后 n 天的行
【发布时间】:2021-11-15 23:14:06
【问题描述】:

我有以下表格和数据:

PatientID   PatientName   Diagnosed  ReportDate   ...
1                         0
1                         0
1                         0
1                         1

因此,每个患者都有多行,因为报告每天出现几次。 每当诊断字段更改为 1 时,对于该患者,我想获取过去 3 天的数据。所以当 Diagnosed ==1 时,获取每个患者的报告时间 -3 天的数据。

SELECT Patients.ReportDate
FROM Patients 
WHERE Diagnosed = 1 and date > ReportDate - interval '3' day;

因此,可以使用 ReportDate - 间隔时间来获取过去 3 天的数据,但是如何根据诊断字段为每个患者指定该数据(因为该患者可以有多个 id)?

我一般是在python中获取csvs后做这个过滤,但是数据集太大了,所以我想先过滤再转成dataframes。

【问题讨论】:

  • 患者和报告是否有单独的相关表格?
  • 所以我只能访问这个 Patient 表,它接收频繁的报告。我应该得到的所有数据都来自这张表。还有另一个唯一 ID 作为字段,因为 PatientID 是重复的,但我只共享了与过滤相关的列。
  • 请显示您的 Postgres 版本 (SELECT version();) 和实际表定义(针对相关列)包括 PK 列、确切的数据类型和约束 (CREATE TABLE ...) 可以 Diagnosed 返回到0 为相同的PatientID(重复)?如果是这样,只报告最新一集?
  • 是的,它会在设定的时间自动接收报告。诊断是基于移动传感器数据自动进行的。因此,如果怀疑它有疾病,它将报告 1,否则它会一直报告 0。我无权更改数据填充方式。我只需要查询并获取感兴趣的信息。因此,每 6 小时,他们系统中的所有患者都会收到一份报告,其中包含“是”或“否”的诊断结果。可以重复不不不,直到怀疑他生病了。这就是为什么我需要查询从他报告生病的那一刻到最近 3 天的数据。

标签: sql postgresql gaps-and-islands


【解决方案1】:

每当诊断字段更改为 1 时,对于该患者,我想获取过去 3 天的数据。

SELECT (p).*
FROM  (
   SELECT p
        , diagnosed
        , bool_or(diagnosed = 1) OVER (w RANGE BETWEEN CURRENT ROW AND '3 days' FOLLOWING) AS in_range
        , lag(diagnosed) OVER w AS last_diagnosed
   FROM   patients p
   WINDOW w AS (PARTITION BY patientid ORDER BY reportdate)
   ) sub
WHERE  diagnosed = 0 AND in_range
    OR diagnosed = 1 AND last_diagnosed = 0
ORDER  BY patientid, reportdate;

db小提琴here

返回“过去 3 天的数据”,其中“字段更改为 1”(前一行为“0”)。

WINDOW 子句只是语法糖,以避免重复拼写相同的窗口定义。 (对性能没有额外的好处。)

SELECT p 在最里面的子查询中是获取整行的好方法。外部SELECT (p).* 返回子查询中未添加辅助列的完整行。这样我们就可以得到整行,而无需拼出所有列(甚至不需要知道所有列)。

RANGE distance PRECEDING/FOLLOWING 需要 Postgres 11 或更高版本。
这是一个较慢的替代方案,也适用于旧版本:

SELECT p.*
FROM  (
   SELECT patientid, reportdate
   FROM  (
      SELECT patientid, reportdate, diagnosed
           , lag(diagnosed) OVER (PARTITION BY patientid ORDER BY reportdate) AS last_diagnosed
      FROM   patients
      ) p0
   WHERE  diagnosed = 1
   AND    last_diagnosed = 0
   ) d
JOIN   patients p USING (patientid)
WHERE  p.reportdate BETWEEN d.reportdate - interval '3 days' AND d.reportdate
ORDER  BY p.patientid, p.reportdate;

子查询d 选择Diagnosed 刚刚切换到1 的行。然后自行加入以选择您的时间范围。

有关 的基础知识,请参阅:

您还添加了:

所以当诊断 ==1 时,获取每个患者的报告时间 -3 天的数据。

这是一个更广泛的定义,Gordon's query 就是这样做的。说明了准确定义需求的重要性。

【讨论】:

    【解决方案2】:

    您可以换一种方式来看待这个问题,即在接下来的三天内是否diagnosed = 1 -- 并取所有行:

    select p.*
    from (select p.*,
                 count(*) filter (where diagnosed = 1) over (partition by patientId order by reportDate range between interval '0 day' following and interval '3 day' following) as cnt_diagnosed_3
          from patients p
         ) p
    where cnt_diagnosed_3 > 0
    order by patientId, reportDate;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-20
      • 2010-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多