我想知道为什么下面的SQL语句的行为方式如下:
select *
from tableA
where document_id in (select document_id
from tableB
where batch_id = 99997)
tableA
包含document_id
列,但tableB
没有,因此查询似乎返回tableA
中的所有行,如果您使用任何字段名称,则会出现此行为IN子句的select语句,它是tableA
中的一个字段。使用不在tableA
或tableB
中的名称会导致错误。
答案 0 :(得分:5)
这不是错误。在子查询中,您仍然可以使用父级列。所以当你说
时SELECT document_id FROM tableB WHERE batch_id = 99997
您说的是表格B中batch_id
为9997的每一行,请从document_id
选择tableA
。当然,所有这些document_id
值都存在,因此它将返回所有这些行。
答案 1 :(得分:3)
这就是为什么我建议您养成为每列添加显式表名的习惯。它对于可维护性或以后扩展查询也很有帮助。
select *
from tableA A
where A.document_id in (select B.document_id
from tableB B
where B.batch_id = 99997)
如果您对这些表进行限定,它将在运行时抛出一个明确的错误并防止任何细微的错误。这会产生类似于
的错误tableB.document_id不存在。
答案 2 :(得分:0)
多年后,我才发现自己的这种行为。我用Exists()代替IN()子句,除了临时和非数据修改查询外,因为过去使用空值会产生意外结果,但这使我感到困惑,直到我阅读了DavidG的响应。完全没有理由以这种方式编写查询:在不引用子查询表的情况下引用外部列,但是语法检查器将不允许这样做。
通常,如果将IN()与子查询一起使用,则您将引用外键,该外键在95%以上的时间中(按照我们公司的标准)与主键同名,但在5%的时间内可以抓住你。
尽管似乎这种行为也存在于Exists()...
Select * from tableA Where Exists(Select document_id from tableB)
... Exists()从来没有这样写过,因为它没有意义,但是写得更明确,就像...
Select * From tableA Where Exists(Select * from tableB tB where tB.TableB_Document_id = tableA.document_id)
,因此发生的可能性较小。
(注意:我会在注释中添加此内容,但我没有要点)