我需要更好地了解关于何时可以在子查询中引用外部表格以及何时(以及为什么)这是不合适的请求的规则.我发现我正在尝试重构的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有时会有重复的记录,所以我需要在我加入t1之前先聚合t2.但是,当我尝试将其包装在子查询中以完成此操作时,突然,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两次(所有的重复需要)?还是在(可能)一个更好的方法来解决这个问题?
提前致谢!
– – – 编辑 – – –
因为有些人猜测到上面的这些查询不是我重构的实际查询,而是我遇到的问题的一个例子.我正在处理的查询更复杂,所以我犹豫不决地将其发布在这里,因为我恐怕会让人失望.
—— UPDATE ——
所以我由一个开发人员跑了,他有一个可能的解释为什么我的子查询失去访问t1.因为我把这个子查询包含在括号里,所以他认为这个子查询是在评估表t1之前被评估的.这肯定会解释“ORA-00904:”t1“.”id“:无效标识符错误我已经收到.这也表明,像操作的算术顺序一样,在语句赋值语句中给予它优先权.如果他们同意/不同意,我仍然会喜欢专家权衡,这是我在这里看到的一个合理的解释.
解决方法
技术注意事项
首先,如果我使用适当的术语来描述我的问题,这将是有帮助的:我上面的第一个语句使用相关的子查询:
> http://en.wikipedia.org/wiki/Correlated_subquery
> http://www.programmerinterview.com/index.php/database-sql/correlated-vs-uncorrelated-subquery/
这实际上是一个相当低效的方式来拉回数据,因为它重新运行外表中每一行的子查询.因此,我将在代码中寻找消除这些类型的子查询的方法:
> https://blogs.oracle.com/optimizer/entry/optimizer_transformations_subquery_unesting_part_1
另一方面,我的第二个声明是在Oracle中使用所谓的内联视图,也称为sql Server中的派生表:
> http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries007.htm
> http://www.programmerinterview.com/index.php/database-sql/derived-table-vs-subquery/
内联视图/派生表在查询开头创建一个临时的未命名视图,然后将其视为另一个表,直到操作完成.因为编译器需要在FROM行上看到这些子查询时创建一个临时视图,所以这些子查询必须是完全独立的,而在子查询之外没有任何引用.
为什么我在做什么是愚蠢的
在第二张表中我想做的是基本上创建一个视图,基于对我的声明的知识之外的另一个表的模糊引用.这就像尝试引用一个表中没有在查询中明确说明的字段.
最后,值得注意的是,Martin提出了一个相当巧妙但最终效率不高的方式来完成我正在努力的工作.应用语句是专有的sql Server函数,但它允许您与衍生表之外的对象进行通信:
> http://technet.microsoft.com/en-us/library/ms175156(v=SQL.105).aspx
同样,这种功能在Oracle中也可以通过不同的语法来实现:
> What is the equivalent of SQL Server APPLY in Oracle?
最终我将重新评估我对这个查询的整个方法,这意味着我将不得不从头开始重建(相信或不是我没有创建这个monstrocity) – 我发誓!非常感谢所有评论者 – 这绝对是让我感到震惊,但是所有的投入都使我在正确的轨道上!