Table A: A1,A2,A_Other Table B: B1,B2,B_Other
在以下示例中,是针对固定值检查的条件,例如,=’ABC’或< 45. 我写了一个如下(1)的查询:
Select * from A Where A1 IN ( Select Distinct B1 from B Where B2 is something And A2 is something );
我真正打算写的是(2):
Select * from A Where A1 IN ( Select Distinct B1 from B Where B2 is something ) And A2 is something;
奇怪的是,两个查询都返回了相同的结果.在查看查询1的解释计划时,看起来就像执行子查询时一样,因为条件A2不适用于子查询,它被推迟用作主查询结果的过滤器.
Select Distinct B1 from B Where B2 is something And A2 is something; --- ERROR: column "A2" does not exist
但我发现情况并非如此,Postgres将不适用的子查询条件推迟到主查询.
这是标准行为还是Postgres异常?这记录在哪里,这个功能叫做什么?
此外,我发现如果我在表B中添加列A2,则只有查询2按预期工作.在这种情况下,查询2中的引用A2仍将引用A.A2,但查询1中的引用将引用新列B.A2,因为它现在可直接应用于子查询.
解决方法
你正在做的是在WHERE子句中编写子查询;不是FROM子句中的内联视图.有区别.
在SELECT或WHERE子句中编写子查询时,可以访问主查询的FROM子句中的表.这不仅仅发生在Postgres中,但它是一种标准行为,可以在所有领先的RDBMS中观察到,包括Oracle,sql Server和MysqL.
运行第一个查询时,优化程序会查看整个查询并确定何时检查哪些条件.正是优化器的这种行为,您看到条件延迟到主查询,因为优化器发现在主查询本身中评估此条件而不影响最终结果更快.
如果只运行子查询,注释掉主查询,则必然会在您提到的位置返回错误,因为找不到要引用的列.
在上一段中,您提到已向表tableB添加了一列A2.你观察到的是正确的.这是因为隐含的参考现象.如果未提及列的表别名,则数据库引擎将首先在子查询的FROM子句中的表中查找该列.仅当在那里找不到列时,才会引用主查询中的表.如果您使用以下查询,它仍将返回相同的结果:
Select * from A aa -- Check the alias Where A1 IN ( Select Distinct B1 from B bb Where B2 is something And aa.A2 is something -- Check the reference );
也许您可以在Korth的关于关系数据库的书中找到更多信息,但我不确定.我刚刚根据我的观察回答了你的问题.我知道这发生了,为什么.我只是不知道如何为您提供进一步的参考资料.