【发布时间】:2013-12-05 01:50:31
【问题描述】:
问题
我需要更好地了解有关何时可以在子查询中引用外部表以及何时(以及为什么)这是不适当的请求的规则。我在尝试重构的 Oracle SQL 查询中发现了一个重复项,但是当我尝试将引用的表转换为分组子查询时遇到了问题。
以下语句适用:
SELECT t1.*
FROM table1 t1,
INNER JOIN table2 t2
on t1.id = t2.id
and t2.date = (SELECT max(date)
FROM table2
WHERE id = t1.id) --This subquery has access to t1
不幸的是,table2 有时会有重复记录,所以我需要先聚合 t2,然后再将其加入 t1。但是,当我尝试将其包装在子查询中以完成此操作时,SQL 引擎突然无法再识别外部表。
SELECT t1.*
FROM table1 t1,
INNER JOIN (SELECT *
FROM table2 t2
WHERE t1.id = t2.id --This loses access to t1
and t2.date = (SELECT max(date)
FROM table2
WHERE id = t1.id)) sub on t1.id = sub.id
--Subquery loses access to t1
我知道这些是根本不同的查询,我要求编译器将它们放在一起,但我不明白为什么一个可以工作,而另一个不行。
我知道我可以在我的子查询中复制表引用并有效地将我的子查询从外部表中分离出来,但这似乎是完成这项任务的一种非常丑陋的方式(代码和处理的所有重复)。
有用的参考资料
我发现了对 SQL Server 中子句执行顺序的精彩描述:(INNER JOIN ON vs WHERE clause)。我正在使用 Oracle,但我认为这将是全面的标准。子句评估有一个明确的顺序(首先是 FROM),所以我认为任何出现在列表后面的子句都可以访问之前处理的所有信息。我只能假设我的第二个查询以某种方式改变了排序,因此我的子查询被评估得太早了?
另外,我发现问了一个类似的问题(Referencing outer query's tables in a subquery ) 但是虽然输入很好,但他们从未真正解释过为什么他不能做他正在做的事情,而只是为他的问题提供了替代解决方案。我已经尝试过他们的替代解决方案,但它给我带来了其他问题。也就是说,带有日期引用的子查询是整个操作的基础,所以我无法摆脱它。
问题
我想了解我在这里做了什么...为什么我的初始子查询可以看到外部表,但在我将整个语句包装在子查询中之后却看不到?
也就是说,如果我试图做的事情无法完成,那么重构第一个查询以消除重复的最佳方法是什么?我应该两次引用 table1 (所有需要的重复项)吗?还是有(可能)更好的方法来解决这个问题?
提前致谢!
-----编辑------
正如一些人推测的那样,上面的这些查询并不是我正在重构的实际查询,而是我遇到的问题的一个示例。我正在处理的查询要复杂得多,所以我不愿在此处发布它,因为我担心它会让人们偏离正轨。
-----更新------
所以我由一位开发人员运行了这个,他有一个可能的解释为什么我的子查询无法访问 t1。因为我将此子查询包装在括号中,所以他认为在评估我的表 t1 之前正在评估此子查询。这肯定会解释我收到的 'ORA-00904: "t1"."id": invalid identifier' 错误。它还表明,就像运算的算术顺序一样,在语句中添加括号会在某些子句评估中赋予它优先级。如果专家同意/不同意这是我在这里看到的合乎逻辑的解释,我仍然希望专家参与进来。
【问题讨论】:
-
无法关联派生表。它必须独立存在。虽然你可以加入它。您可以在需要某种相关派生表的地方使用
APPLY。 -
马丁....真诚的,谢谢!根据您的评论,我能够进行一些额外的研究,发现我的查询实际上并没有按照我最初的想法提取数据。此外,您使用 Apply 的建议似乎非常适用(尽管对我而言,语法与我使用 Oracle 时略有不同)。非常感谢您的建议 - 事实上,如果您将其作为答案提交,我会将其标记为正确的。
标签: sql subquery correlated-subquery derived-table inline-view