【问题标题】:How to do a SQL group with date gap如何做一个有日期间隔的 SQL 组
【发布时间】:2011-03-15 17:24:36
【问题描述】:

我有以下疑问:

 SELECT patient_id FROM patient_visit where visit_type in ('A', 'B', 'C') 
 group by patient_id having count(*) >= 2

获取至少进行过两次“A”、“B”或“C”类型就诊的所有患者的列表。

patient_visit 表还有一个 visit_date 列,用于存储就诊日期。我的问题:是否可以在不删除 group by 语句的情况下修改上述查询以查询“所有至少有两次就诊的患者,并且这两次就诊中的任何一次的差距为 60 天数”?

谢谢!

P.S.:我使用的是 Oracle,如果有内置函数,我也可以使用。

【问题讨论】:

  • 大概您的意思是“这两次连续访问中的任何一次”,而不仅仅是“这两次访问中的任何一次”(即您不是在寻找使用 MAXMIN 的答案)
  • 为什么限制保留组?
  • @Martin 最好是任意两个日期
  • @Shannon 我有这个限制,因为这个语句是通过 XML 到 SQL 编译器生成的代码。保留 Group by 语句将使其对代码生成器进行简单的更改。

标签: sql oracle group-by aggregate aggregate-functions


【解决方案1】:

任意两个日期,所以第一次和最后一次访问都符合条件?

SELECT patient_id
FROM patient_visit
where visit_type in ('A', 'B', 'C') 
group by patient_id
having count(*) >= 2 AND MAX(visit_date) - MIN(visit_date) >= 60

如果你的意思是连续的,那么

SELECT patient_id
FROM patient_visit
where visit_type in ('A', 'B', 'C') 
  AND EXISTS (
    select *
    from patient_visit v
    where v.visit_type in ('A', 'B', 'C')
      and v.patient_id = patient_visit.patient_id
      and v.visit_date >= patient_visit.visit_date + 60)
  AND NOT EXISTS (
    select *
    from patient_visit v2
    where v2.visit_type in ('A', 'B', 'C')
      and v2.patient_id = patient_visit.patient_id
      and v2.visit_date > patient_visit.visit_date
      and v2.visit_date < patient_visit.visit_date + 60)
group by patient_id

这是一个昂贵的查询,大约为 O(N3)。 Oracle LAG 版本可能会更快。

【讨论】:

    【解决方案2】:
    SQL> create table patient_visit (patient_id number(38) not null
      2      , visit_type varchar2(1) not null
      3      , visit_date date not null);
    
    Table created.
    
    SQL> insert into patient_visit
      2  select 1, 'A', date '2010-01-01' from dual
      3  union all select 1, 'D', date '2010-01-02' from dual
      4      -- ignore, by type
      5  union all select 1, 'C', date '2010-01-01' + 60 from dual
      6      -- 1 is included
      7  union all select 1, 'B', date '2011-01-01' from dual
      8      -- don't include 1 more than once
      9  union all select 2, 'A', date '2010-01-01' from dual
     10  union all select 2, 'B', date '2010-01-02' from dual
     11      -- breaks up 60 day gap.
     12  union all select 2, 'C', date '2010-01-01' + 60 from dual;
    
    7 rows created.
    
    SQL> commit;
    
    Commit complete.
    
    SQL> select patient_id
      2  from (select patient_id
      3          , visit_date
      4          , lag(visit_date) over (partition by patient_id
      5              order by visit_date) prior_visit_date
      6      from patient_visit
      7      where visit_type in ('A', 'B', 'C'))
      8  where visit_date - prior_visit_date >= 60
      9  group by patient_id;
    
    PATIENT_ID
    ----------
             1
    
    SQL> spool off
    

    【讨论】:

      【解决方案3】:

      我没有要测试的 oracle,但我认为这会起作用

      select patient_id from 
         (SELECT patient_id, dateField FROM patient_visit where visit_type in ('A','B', 'C') 
         group by patient_id having count(*) >= 2) as temp 
      where temp.dateField > '2011-01-01'
      

      【讨论】:

      • 一方面,如果不是通过子查询返回,则不能在 dateField 上进行选择。
      猜你喜欢
      • 2021-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-21
      • 1970-01-01
      • 1970-01-01
      • 2012-03-26
      相关资源
      最近更新 更多