2011-09-29 62 views
1

我無法從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)。例如,我想抓住= 5的病人123的最新系列鏡頭,因此我希望返回此例中的前四個記錄(所有列應在這些行中返回)。最後兩項應該省略,因爲2011年1月1日開始了一系列新的拍攝。無論如何,我有一個algortihm的想法,但我無法編寫查詢。它會像這樣:

  1. 獲得患者123的最大日期,shot_id = 5。返回該行並查看其系列(在本例中爲'B')。

  2. 從最大日期獲取下一個最低日期並查看其系列(在本例中爲'3')。如果該系列在1和B之間,則返回該行。如果不存在其他記錄,則結束查詢。

  3. 從步驟2獲取下一個最低日期並查看其系列(在本例中爲'2')。如果該系列小於第2步中的系列,則返回該行。否則,結束查詢。

你繼續,直到你得到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 

這個查詢看起來很複雜,但也許我只是在推翻它。感謝你們的時間。

+0

因此,如果有下面的第一條記錄更加強注射,你想那些返回呢? – NullUserException

+0

我還認爲,如果你只是用數字記錄系列中的所有鏡頭,而不是使用'B'作爲助推器,它會更容易。 – NullUserException

+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); 
+0

如果系列1鏡頭是在其他地方給出的,因此不在db中怎麼辦? – RedFilter

+0

@RedFilter:這個新版本解決了這個問題。 – Benoit

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

聽起來這應該滿足你的要求:

select Patient_ID, Shot_ID, Series, max(Date_Taken) 
from Vaccinations 
where Patient_ID=123 and Shot_ID=5 
group by Patient_ID, Shot_ID, Series 

where子句可以省略返回所有患者和拍攝。

+0

也許在前一個shot_id的「系列」中可能會有更多的項目比後者更多? – Benoit

+0

@Benoit,你能澄清你的陳述嗎? –

+0

請問誰能降低離職原因的解釋? –

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系列有問題

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 
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`