Сложный запрос Oracle с указанием максимальной даты - PullRequest
1 голос
/ 29 сентября 2011

У меня проблемы с получением нужных данных из базы данных 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, поэтому я хотел бы вернуть первые четыре записи в этом случае (все столбцы должны быть возвращены в этих строках). Последние два должны быть опущены, потому что новая серия снимков была запущена 01.01.2011. В любом случае, я имею в виду алгоритм, но у меня проблемы с написанием запроса. Это будет выглядеть примерно так:

  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

Этот запрос кажется довольно сложным, но, может быть, я просто его обдумал Спасибо за ваше время.

Ответы [ 5 ]

0 голосов
/ 21 февраля 2014
 `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`
0 голосов
/ 29 сентября 2011

В этом запросе игнорируются любые снимки, если есть новые снимки с такой же или меньшей серией (для одинаковых 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 голосов
/ 29 сентября 2011

Я бы взял двусторонний подход.Сделайте самый последний снимок «серии 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)
0 голосов
/ 29 сентября 2011
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 голосов
/ 29 сентября 2011

Я бы сделал:

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 );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...