FROM 列表中的 Oracle 相关子查询
Posted
技术标签:
【中文标题】FROM 列表中的 Oracle 相关子查询【英文标题】:Oracle correlated subquery in FROM list 【发布时间】:2009-03-04 17:44:43 【问题描述】:我刚刚尝试在 Oracle 中的 SELECT
语句的 FROM
子句中执行关联子查询,但我收到一个错误,表明我无法执行关联(大意为 Obs.pID
未被识别)。
这应该有效吗?
FROM ml.Person Person
JOIN ml.Obs ON Person.pID = Obs.pId
JOIN (SELECT ObsMax2.pId, ObsMax2.hdId
, MAX(ObsMax2.obsDate) as maxDate
FROM ml.Obs ObsMax2
WHERE ObsMax2.pId = Obs.pId
AND ObsMax2.obsDate < ?EndDate
GROUP BY ObsMax2.pId, ObsMax2.hdId) ObsMax
ON Obs.pId = ObsMax.pId
AND Obs.hdId = ObsMax.hdId
AND Obs.obsDate = ObsMax.maxDate
我的解决方法似乎是使它成为一个不相关的子查询,并向子查询添加条件,以防止它完全运行 amuck、amuck、amu--oof 抱歉。
不过,如果可能的话,我宁愿弄清楚如何正确关联它 - 像该子查询一样工作的视图需要永远构建。
【问题讨论】:
您可能想要重构查询,而不仅仅是修复您遇到的这个语法问题。考虑在问题中添加关于您要完成的任务的说明。 @David - "Pedant" :-) @Alan - 我只是不确定我应该在多大程度上谈论这个系统的内部结构。通常,我会使用按 pID/hdID 进行分组的内置视图来获取最新的观察结果 - 但如果它是在 2009 年并且您正在查询 2008 年,则会失败。 【参考方案1】:您可以通过使用分析函数来确定每个 pid 和 hdid 的最大 obsDate 来实现这部分查询的意图。
应该是这样的:
select ...
from (
SELECT pId,
hdId,
obsDate
MAX(obsDate) over (partition by pId, hdId) maxDate
FROM ml.Obs
WHERE obsDate < ?EndDate
)
where obsDate = maxDate
/
【讨论】:
这个版本的解释方案比我想出来的要好一点,感觉也更快。我以前没有遇到过这些——谢谢! 您刚刚向我展示了如何使用 PARTITION BY,并解决了我的问题。【参考方案2】:FROM 子句中的子查询不能引用同一 FROM 子句中的其他表。删除 ObsMax2.pId = Obs.pId 子句应该可以解决问题,并且据我所知,由于相同的子句处于连接条件中,因此会给出完全相同的结果。但是,正如您所提到的,您可能会在子查询中使用 GROUP BY 时遇到性能问题。
据我所知,您正试图从 ml.Obs 中获取单个 pID/hdId 记录,其最大 obsDate 小于 EndDate。在这种情况下,如何将子查询移到可以关联它的 WHERE 子句中呢?例如:
select ...
from
ml.Person Person
join ml.Obs on Person.PID = Obs.pId
where Obs.obsDate = (
select max(obsDate)
from ml.Obs Obs2
where Obs2.pId = Obs.pId
and obs2.hdId = Obs.hdId
and Obs2.obsDate < EndDate)
【讨论】:
如果是这种情况,特别是如果该字段仅为日期类型,请注意可能返回多个人(因为重复日期)。 是的,如果 (pId, hdId, obsDate) 组合不是唯一的,那么每个 (pId, hdId) 对可以获得多条记录。我相信原始查询也会有同样的问题。 这是对 EMR(医疗记录)系统的查询。 pId 是 PersonId,hdId 标识医学观察结果(BP、Pulse、LDL 等)。因此,您不必(过多)担心重复 pid/hdid/date - 每个文档都有一个值。 但我认为这行不通 - 您可能需要两天不同的观察结果(一次访问时的 BMI 百分位数,另一次访问哮喘监测)。除非我遗漏了一些关于相关性的东西,这总是有可能的...... 关联在所有三列上完成。基本查询将从 ml.Obs 中检索一个人的所有行。然后,子查询选择 obsdate 是给定 pId、hdId 的 max() 的行。请参阅 David Aldridge 的答案以了解对此的变化(性能可能会有所不同)。【参考方案3】:您已经为许多表格添加了前缀“ml”。但并非无处不在(例如,第一次加入)。假设您需要(对于用户/权限/其他):
在 Person.pID 上加入 ml.Obs = **ml.**Obs.pId
或
加入 ml.Obs Obs ON Person.pID = Obs.pId
还有其他地方也需要这样做。
如果不是这种情况,请将它们从您的查询中删除,因为它们无关紧要且会分散注意力。
【讨论】:
以上是关于FROM 列表中的 Oracle 相关子查询的主要内容,如果未能解决你的问题,请参考以下文章