小编典典

SQL-子查询和外部表之间的关系

sql

问题

我需要更好地了解有关何时可以在子查询中引用外部表以及何时(以及为什么)不适当的请求的规则。我在尝试重构的Oracle
SQL查询中发现一个重复项,但是当我尝试将引用的表转换为分组的subQuery时遇到了问题。

以下语句可以正常工作:

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与WHERE子句。我使用的是Oracle,但我认为这将是全面的标准。子句评估有明确的顺序(首先是FROM),因此我认为任何出现在列表后面的子句都可以访问以前处理过的所有信息。我只能假设我的第二个查询以某种方式改变了顺序,以至于我的子查询被评估为时过早?

  • 另外,我发现了一个类似的问题在子查询中引用外部查询的表,但是尽管输入很好,但是他们从来没有真正解释过为什么他不能做自己所做的事情,而只是给出了解决问题的替代方案。我已经尝试过他们的替代解决方案,但这给我带来了其他问题。即,带有日期引用的子查询是整个操作的基础,因此我无法摆脱它。

问题

  • 我想了解我在这里所做的事情…为什么我的初始子查询可以看到外部表,但是在将整个语句包装在子查询中之后却看不到外部表?

  • 就是说,如果我想做的事情无法完成,重构第一个查询以消除重复的最佳方法是什么?我是否应该两次引用table1(包括所有需要的重复项)?还是有(可能)解决这个问题的更好方法?

提前致谢!

- - - 编辑 - - -

正如一些人推测的那样,以上这些查询不是我正在重构的实际查询,而是我所遇到的问题的一个示例。我正在使用的查询要复杂得多,因此我很犹豫将其发布在这里,因为我担心它会使人们误入歧途。

- - - 更新 - - -

因此,我由一位开发人员执行了此操作,他对我的子查询为什么无法访问t1有一个可能的解释。因为我将这个子查询用括号括起来,所以他认为在评估表t1之前先对这个子查询进行了评估。这肯定可以解释我收到的“
ORA-00904:“ t1”。“id”:无效标识符“错误。它还建议像运算的算术顺序一样,在语句中添加括号会使其在某些子句评估中具有优先权。如果他们同意/不同意,这仍然是我在这里看到的合乎逻辑的解释,我仍然希望专家能对此有所帮助。


阅读 301

收藏
2021-03-23

共1个答案

小编典典

因此,我根据马丁·史密斯(Martin Smith)在上面所做的评论(谢谢马丁!)来弄清了这一点,并希望确保将我的发现分享给其他遇到此问题的人。

技术注意事项

首先,如果我使用正确的术语来描述我的问题,那肯定会有所帮助:上面的第一条语句使用了 相关的子查询

实际上,这是一种回退数据的效率很低的方式,因为它为外部表中的每一行重新运行子查询。因此,我将寻找在我的代码中消除这些子查询类型的方法:

另一方面,我的第二条语句使用的是Oracle中的 内联视图 ,在SQL Server中也称为 派生表

内联视图/派生表在查询开始时会创建一个临时的未命名视图,然后将其视为另一个表,直到操作完成。因为编译器需要在FROM行上看到这些子查询时创建一个临时视图,所以这些子
查询必须完全独立, 并且在子查询之外没有任何引用。

为什么我在做的事很愚蠢

我在第二张表中试图做的基本上是基于对另一个表的不明确引用创建一个视图,该表超出了我的陈述范围。这就像试图引用您在查询中未明确说明的表中的字段一样。

解决方法

最后,值得注意的是,马丁提出了一种相当聪明但最终效率低下的方式来完成我想做的事情。

最终,我将重新评估该查询的整个方法,这意味着我将不得不从头开始重建它(信不信由你,我最初并没有创造出这种怪异的东西-我发誓!)。
非常感谢所有发表评论的人 -这肯定让我很沮丧,但是所有的投入都使我走上了正确的道路!

2021-03-23