问题
我需要更好地理解在子查询中何时可以引用外部表,以及为什么这种请求是不合适的。我发现了一个正在尝试重构的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”:无效标识符”的错误。这也表明,与算术运算顺序一样,在语句中添加括号会在某些子句评估中赋予它优先权。如果有专家在这方面表示同意/不同意,我仍然很想听听他们的意见。
APPLY
。 - Martin Smith