涉及最大日期的复杂Oracle查询

时间:2011-09-29 15:18:08

标签: sql oracle

我无法从Oracle数据库获取我想要的数据。任何帮助将不胜感激。这是我的表格的样本:

Table: Vaccinations

Patient_ID | Shot_ID | Series | Date_Taken
-------------------------------------------
123        | 5       | B      | 8/1/2011
123        | 5       | 3      | 2/1/2011
123        | 5       | 2      | 1/10/2011
123        | 5       | 1      | 1/1/2011
456        | 3       | 2      | 1/10/2011
456        | 3       | 1      | 1/1/2011
123        | 5       | 2      | 10/1/2010
123        | 5       | 1      | 9/1/2010

系列列指示针对特定Shot_ID管理的镜头。 “B”表示给予助推器,“2”表示第二个,“1”表示第一个,依此类推,但“3”表示最大值,然后是助推器。对于特定类型的镜头(Shot_ID),我正在尝试为患者抓取所有最新系列的镜头。例如,我想抓住患者123的Shot_ID = 5的最新系列镜头,所以我想在这种情况下返回前四个记录(所有列应该在这些行中返回)。最后两个应该省略,因为2011年1月1日开始了一系列新镜头。无论如何,我有一个algortihm,但我在编写查询时遇到了麻烦。它会是这样的:

  1. 获取患者123的最长日期shot_id = 5。返回行并查看其系列(在本例中为“B”)。

  2. 从最大日期获取下一个最低日期并查看其系列(在本例中为“3”)。如果系列介于1和B之间,则返回该行。如果不存在其他记录,则结束查询。

  3. 从第2步获取下一个最低日期并查看其系列(在本例中为“2”)。如果系列小于步骤2中的系列,则返回该行。否则,请结束查询。

  4. 你继续重复这些步骤,直到你到达series = 1,这将返回或直到你达到一个大于或等于当前系列的系列,这个系列不会被返回。因此,输出应如下所示:

    123 | 5 | B | 8/1/2011
    123 | 5 | 3 | 2/1/2011
    123 | 5 | 2 | 1/10/2011
    123 | 5 | 1 | 1/1/2011
    

    这个查询似乎相当复杂,但也许我只是在思考它。谢谢你们的时间。

5 个答案:

答案 0 :(得分:0)

我愿意:

SELECT v1.* FROM vaccinations v1
  LEFT JOIN vaccinations v2
    ON v2.patient_id = v1.patient_id AND v2.shot_id = v1.shot_id
   AND v2.series = '1' AND v2.date_taken > v1.date_taken
 WHERE v2.series IS NULL
   AND v1.patient_id = '123'
   AND v1.shot_id = '5';

左连接查找更近期的新镜头的开始。如果它没有返回任何行(IS NULL),那么这是最新的镜头。这相当于:

SELECT * FROM vaccinations v1
 WHERE patient_id = '123'
   AND shot_id = '5'
   AND NOT EXISTS (SELECT NULL FROM vaccinations v2
                    WHERE v2.patient_id = v1.patient_id AND v2.shot_id = v1.shot_id
                      AND v2.series = '1' AND v2.date_taken > v1.date_taken
                  );

如果最新系列不一定以1开头,那么:

WITH all_series AS
   ( SELECT rownum rn, series, date_taken
       FROM vaccinations
      WHERE patient_id = '123' AND shot_id = '5' AND series <> 'B'
      ORDER BY date_taken ASC
   )
   , last_series_beginning AS
   ( SELECT MAX(as1.date_taken) x
       FROM all_series as1
       LEFT JOIN all_series as2        -- we need to keep first row in as1
         ON as2.rn = as1.rn - 1
      WHERE as1.series < as2.series
         OR as1.rn = 1
   )
SELECT * FROM vaccinations
 WHERE patient_id = '123' AND shot_id = '5'
   AND date_taken > ( SELECT x FROM last_series_beginning );

答案 1 :(得分:0)

我采取双管齐下的方法。获取最新的“系列1”镜头,然后获得所有后续系列。

SELECT Patient_ID, Shot_ID, Series, Date_Taken
    FROM Vaccinations v
    WHERE Patient_ID = 123
        AND Shot_ID = 5
        AND Date_Taken >= (SELECT MAX(Date_Taken)
                               FROM Vaccinations v
                               WHERE Patine_ID = 123
                                   AND Shot_ID = 5
                                   AND Series = 1)

答案 2 :(得分:0)

select * from vaccinations as v
  inner join (
    select a.series , max(a.date_taken) as max_date
      from vaccinations as a, vaccinations as b 
      where a.series = b.series 
            and not exists (
              select * from vaccinations as c where c.series = a.series 
                       and c.date_taken between a.date_taken and b.date_taken)) as m
    on v.date_taken >= m.max_date and patient_id = 123 and shot_id = 5

不存在 - 保持重复序列对开始(或停止)...但如果只有1个系列存在问题

答案 3 :(得分:0)

此查询会忽略任何具有相同或更低系列的新镜头(对于相同的Patient_ID和Shot_ID):

select s.*
from Shot s
inner join (
    select Patient_ID, Shot_ID, max(Date_Taken) as MaxDate
    from Shot
    group by Patient_ID, Shot_ID
) sm on s.Patient_ID = sm.Patient_ID and s.Shot_ID = sm.Shot_ID
inner join Shot s2 on sm.Patient_ID = s2.Patient_ID and sm.Shot_ID = s2.Shot_ID and sm.MaxDate = s2.Date_Taken
where (s.Date_Taken = sm.MaxDate
        or (
            case when s.Series = 'B' then 4 else s.Series end < case when s2.Series = 'B' then 4 else s2.Series end
            and not exists (
                select 1 
                from Shot
                where Date_Taken > s.Date_Taken
                    and Shot_id = s.Shot_ID
                    and case when Series = 'B' then 4 else Series end <= case when s.Series = 'B' then 4 else s.Series end
            )
        )
    )
    and s.Patient_ID = 123  

答案 4 :(得分:0)

 `select A.patient_id , A.shot_id , A.series , max(date_taken)
From cs_study A
inner join 
(
select  max(shot_id) max_shotid, patient_id from cs_study
group by patient_id 
) b
on A.shot_id =B.max_shotid
and a.patient_id = B.patient_id 
group by A.patient_id , A.shot_id , A.series`