在Oracle中映射最近的日期

时间:2019-01-23 13:51:12

标签: oracle

enter image description here我正在尝试联接两个带有最近日期的表。请参阅屏幕截图以供参考。

我有药物表和副作用表,我需要了解特定副作用的医疗位置。

示例1:药物从2015-07-23(药物治疗表中的第二行)开始,并且在2015-07-24(药物副作用表中的第二行)有副作用。因此,这告诉我医疗位置为 ABDOMEN

例2:药物治疗于2018-06-19(药物治疗表的最后一行)开始,并且在2018-07-25(药物副作用表的最后一行)出现了副作用。因此,这告诉我医疗位置为 THIGH

因此,在这里,我只是试图映射两个表的最近日期,并在结果表中获取特定的医疗位置。

当我以以下方式编写联接时: MID = SID AND MNAME = SNAME AND药物治疗开始日期<=副作用日期那么我得到的记录太多了。好像我缺少在这里写的条件。您能帮我吗?

谢谢。

Medication Table:
MID     MNAME       MedicalLocation   Medication Start Date
I1F-BE  132~1201    THIGH             2015-07-07
I1F-BE  132~1202    ABDOMEN           2015-07-23
I1F-BE  132~1203    ABDOMEN           2015-08-04
I1F-BE  132~1204    ABDOMEN           2015-08-18
I1F-BE  132~1205    ABDOMEN           2015-09-01
I1F-BE  132~1206    ABDOMEN           2015-09-15
I1F-BE  132~1207    ABDOMEN           2015-09-29
I1F-BE  132~1208    ABDOMEN           2015-10-13
I1F-BE  132~1209    THIGH             2015-10-27
I1F-BE  132~1210    ABDOMEN           2015-11-10
I1F-BE  132~1201    THIGH             2018-06-19
I1F-BE  132~1209    THIGH             2015-10-27
I1F-BE  132~1210    ABDOMEN           2015-11-10
I1F-BE  132~1201    THIGH             2018-06-19

副作用表:

SID     SNAME        Side Effect             Side Effect Start Date
I1F-BE  132~1201    UTI                      2015-06-23
I1F-BE  132~1202    Injection Site Reaction  2015-07-24
I1F-BE  132~1203    Injection Site Reaction  2015-08-05
I1F-BE  132~1204    Viral Syndrome           2015-08-10
I1F-BE  132~1205    Injection Site Reaction  2015-08-18
I1F-BE  132~1206    Injection Site Reaction  2015-09-02
I1F-BE  132~1207    Injection Site Reaction  2015-09-16
I1F-BE  132~1208    Injection Site Reaction  2015-09-30
I1F-BE  132~1209    Injection Site Reaction  2015-10-14
I1F-BE  132~1210    Injection Site Reaction  2015-10-28
I1F-BE  132~1201    Basal Cell carcinoma     2018-07-25

2 个答案:

答案 0 :(得分:2)

联接方法对于中小型表工作正常,但在较大表上的性能较差。问题是您必须将所有具有所有副作用的药物都加入,只能丢弃除最接近的组合以外的所有药物。

应该缩放的另一种方法是对两个表使用统一的视图,并使用分析功能查找LAG记录以获取位置。

此查询生成统一视图。请注意,添加了新列SOURCE_TYPE以区分行源。

with tab as (
select SID, SNAME, START_DATE, 'SIDE_EFFECT' source_type,cast (null as varchar2(25)) MEDICALLOCATION,  SideEffect from SideEffect
union all
select MID, MNAME, START_DATE, 'MEDICATION' source_type, MEDICALLOCATION, null as SideEffect from Medication
)
select SID, SNAME, START_DATE, SOURCE_TYPE, MEDICALLOCATION, SIDEEFFECT 
from tab
where SID = 'I1F-BE' and SNAME = '132~1202'
order by 1,2,3;

SID        SNAME      START_DATE          SOURCE_TYPE MEDICALLOCATION           SIDEEFFECT              
---------- ---------- ------------------- ----------- ------------------------- -------------------------
I1F-BE     132~1202   23.07.2015 00:00:00 MEDICATION  ABDOMEN                                             
I1F-BE     132~1202   24.07.2015 00:00:00 SIDE_EFFECT                           Injection Site Reaction   

SIDE_EFFECT记录(如果直接由MEDICATION记录开头,则唯一需要的逻辑是从滞后记录中获取MEDICALLOCATION列的值。

分析功能LAG在连接键列上使用PARTITION BYORDER BYstart_date定义。

将位置移动到site_effect行之后,您可以丢弃所有用药记录。

最终查询

with tab as (
select SID, SNAME, START_DATE, 'SIDE_EFFECT' source_type,cast (null as varchar2(25)) MEDICALLOCATION,  SideEffect from SideEffect
union all
select MID, MNAME, START_DATE, 'MEDICATION' source_type, MEDICALLOCATION, null as SideEffect from Medication
),
tab2 as (
select SID, SNAME, START_DATE, SOURCE_TYPE, MEDICALLOCATION,  SIDEEFFECT,
CASE when SOURCE_TYPE = 'SIDE_EFFECT' and
          lag(SOURCE_TYPE) over (partition by  SID, SNAME order by START_DATE) = 'MEDICATION' then 
     lag(MEDICALLOCATION) over (partition by  SID, SNAME order by START_DATE)
END as SIDEEFFECT_MEDICALLOCATION  
from tab)
select SID, SNAME, START_DATE, SIDEEFFECT, SIDEEFFECT_MEDICALLOCATION 
from tab2
where source_type = 'SIDE_EFFECT' 
order by 1,2,3;

SID        SNAME      START_DATE          SIDEEFFECT                SIDEEFFECT_MEDICALLOCATION
---------- ---------- ------------------- ------------------------- --------------------------
I1F-BE     132~1201   23.06.2015 00:00:00 UTI                                                  
I1F-BE     132~1201   25.07.2018 00:00:00 Basal Cell carcinoma      THIGH                      
I1F-BE     132~1202   24.07.2015 00:00:00 Injection Site Reaction   ABDOMEN                    
I1F-BE     132~1203   05.08.2015 00:00:00 Injection Site Reaction   ABDOMEN                    
I1F-BE     132~1204   10.08.2015 00:00:00 Viral Syndrome  
...

答案 1 :(得分:1)

听起来您想从“药物治疗”表中获得该行,该行的最大药物治疗日期<=副作用日期。这是一种非常常见的SQL模式:有关响应很好的示例,请参见this question

我为您提供了一些建议。第一个方法是幼稚的编写方式-适用于所有Oracle版本。一个可能要考虑的问题:当“最接近的日期”与开始日期相同的两种药物匹配时,您想怎么办?该查询将为每个匹配项返回一行,该行可能比您期望的要多。

select s.*, m.MedicalLocation
from side_effects s
left join medication m
  on m.mid = s.sid
  and m.mname = s.sname
  and m.medication_start_date = (
    select max(medication_start_date)
    from medication m2
    where m2.mid = m.mid
      and m2.mname = m.mname
      and m2.medication_start_date <= s.side_effect_date)
;

您还可以使用fetch first 1 row only子句在Oracle 12c及更高版本上更简单地编写此代码。这样可以确保每个副作用仅获得1个用药记录-如果您有两个匹配项,Oracle将根据行在磁盘上的排列方式选择一个。

select s.*, 
    (select m.MedicalLocation
     from medication m
     where m.mid = s.sid
       and m.mname = s.sname
       and m.medication_start_date <= s.side_effect_date
     order by m.medication_start_date desc
     fetch first 1 row only) as MedicalLocation
from side_effects s
;

您还可以查看我链接的问题的其他答案,以了解其他方法,例如

select s.*, max(m.MedicalLocation) KEEP (DENSE_RANK FIRST ORDER BY m.medication_start_date desc) as MedicalLocation
from side_effects s
left join medication m
  on m.mid = s.sid
  and m.mname = s.sname
  and m.medication_start_date <= s.side_effect_date
;