问题
我需要更好地理解有关何时可以在子查询中引用外部表以及何时(以及为什么)这是不适当的请求的规则。我在尝试重构的 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 子句)。我正在使用 Oracle,但我认为这将是全面的标准。子句评估有一个明确的顺序(首先是 FROM),所以我认为任何出现在列表后面的子句都可以访问之前处理的所有信息。我只能假设我的第二个查询以某种方式改变了排序,因此我的子查询被评估得太早了?
此外,我发现了一个类似的问题(在子查询中引用外部查询的表 ),但是虽然输入很好,但他们从未真正解释过为什么他不能做他正在做的事情,而只是为他的问题提供了替代解决方案。我已经尝试过他们的替代解决方案,但这给我带来了其他问题。也就是说,带有日期引用的子查询是整个操作的基础,所以我无法摆脱它。
问题
我想了解我在这里做了什么......为什么我的初始子查询可以看到外部表,但在我将整个语句包装在子查询中之后却看不到?
也就是说,如果我想做的事情无法完成,那么重构第一个查询以消除重复的最佳方法是什么?我应该两次引用 table1 (所有需要的重复项)吗?还是(可能)有更好的方法来解决这个问题?
提前致谢!
- - - 编辑 - - -
正如一些人推测的那样,上面的这些查询并不是我正在重构的实际查询,而是我遇到的问题的一个例子。我正在处理的查询要复杂得多,所以我很犹豫在这里发布它,因为我担心它会让人们偏离正轨。
- - - 更新 - - -
所以我由一位开发人员运行了这个,他对为什么我的子查询失去对 t1 的访问权有一个可能的解释。因为我将此子查询包装在括号中,所以他认为在评估我的表 t1 之前正在评估此子查询。这肯定会解释我收到的 'ORA-00904: "t1"."id": invalid identifier' 错误。它还表明,就像运算的算术顺序一样,在语句中添加括号会在某些子句评估中赋予它优先级。如果他们同意/不同意这是对我在这里看到的情况的合乎逻辑的解释,我仍然希望专家参与进来。