我正在尝试联接两个带有最近日期的表。请参阅屏幕截图以供参考。
我有药物表和副作用表,我需要了解特定副作用的医疗位置。
示例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
答案 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 BY
,ORDER BY
由start_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
;