sql - IN 子查询的 WHERE 条件影响主查询——这是一个特性还是一个错误?

标签 sql postgresql subquery postgresql-9.1 in-subquery

假设两个表:

Table A: A1, A2, A_Other
Table B: B1, B2, B_Other

在以下示例中, is something 是根据固定值检查的条件,例如 = '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 is something不适用于子查询,它被延迟用作主查询结果的过滤器。

我通常希望查询 1 失败,因为子查询本身 会失败:

Select Distinct B1 from B
Where B2 is something
And A2 is something; --- ERROR:  column "A2" does not exist

但我发现情况并非如此,Postgres 将不适用的子查询条件推迟到主查询。

这是标准行为还是 Postgres 异常? 这个记录在哪里,这个功能叫什么?

此外,我发现如果我添加一列 A2在表中B ,只有查询 2 按原计划工作。在这种情况下引用 A2在查询中 2 仍会引用 A.A2 ,但查询 1 中的引用将引用新列 B.A2因为它现在直接适用于子查询。

最佳答案

这是一个很好的问题,很多人都遇到过但懒得停下来看看的问题。

你正在做的是在 WHERE 子句中写一个子查询;不是 FROM 子句中的内联 View 。这是有区别的。

当您在SELECTWHERE 子句中编写子查询时,您可以访问主查询的FROM 子句中的表.这不仅发生在 Postgres 中,而且是一种标准行为,可以在所有领先的 RDBMS 中观察到,包括 Oracle、SQL Server 和 MySQL。

当您运行第一个查询时,优化器会检查您的整个查询并确定何时检查哪些条件。正是优化器的这种行为让您看到条件被延迟到主查询,因为优化器发现在主查询本身中评估这个条件更快而不影响最终结果。

如果你只运行子查询,注释掉主查询,它必然会在你提到的位置返回一个错误,因为找不到被引用的列。

在你的最后一段中,你提到你添加了一个列 A2 到表 tableB。你所观察到的是正确的。发生这种情况是因为隐式引用现象。如果您没有提及列的表别名,数据库引擎将首先在子查询的 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 关于关系数据库的书中找到更多信息,但我不确定。我刚刚根据我的观察回答了你的问题。我知道会发生这种情况以及原因。我只是不知道如何才能为您提供进一步的引用。

关于sql - IN 子查询的 WHERE 条件影响主查询——这是一个特性还是一个错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20603404/

相关文章:

sql - 在 PostgreSQL 中为每个客户选择最后两条记录

mysql - 从两个连接表中查询总和的性能最明智的查询

sql - 如何在子查询中使用 FOR XML?

ruby-on-rails - 为什么这两个查询以不同的顺序检索记录?

sql - 如何在plsql中动态定义类型

sql - PostgreSQL 中的类型比较,如何比较 bigint 等 ..?

mysql - SQL插入多行,但只执行一次子查询

mysql - 在子查询中使用in参数?

mysql - 如何编写查询以从 SQLite/MySQL 检索最后更新的行?

python - Pyodbc 驱动程序为空