【问题标题】:Complex Oracle query involving max date涉及最大日期的复杂 Oracle 查询
【发布时间】:2014-02-21 22:55:08
【问题描述】:

我无法从 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 日开始的。无论如何,我有一个算法,但我在编写查询时遇到了麻烦。它会是这样的:

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

  2. 从 Max Date 中获取下一个最低日期并查看其系列(在本例中为“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

这个查询似乎很复杂,但也许我只是想多了。谢谢大家的时间。

【问题讨论】:

  • 那么,如果在你的第一张唱片之后还有更多的助推器,你是否也希望它们也被退回?
  • 我还认为,如果您只记录系列中的所有镜头及其编号,而不是使用B 作为助推器,会更容易。
  • 是的,如果在第一条记录之后还有更多的助推器,我希望也能返回。

标签: sql oracle


【解决方案1】:

我会采取双管齐下的方法。获取最新的“系列 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】:

    此查询将忽略任何具有相同或更低系列的较新镜头(对于相同的 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  
    

    【讨论】:

      【解决方案3】:
      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 个系列有问题

      【讨论】:

        【解决方案4】:

        我愿意:

        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 的镜头是在其他地方拍摄的,因此不在数据库中怎么办?
        • @RedFilter:这个新版本解决了这个问题。
        【解决方案5】:
         `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`
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-07-26
          • 2018-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多