Sql 在左连接中放置条件的背后是什么
我有两个类似的select语句,它们返回不同数量的行 选择1:Sql 在左连接中放置条件的背后是什么,sql,oracle,Sql,Oracle,我有两个类似的select语句,它们返回不同数量的行 选择1: select count(*) from table_1 a left join table_2 b on a.column_1 = b.column_1 and b.column_2 = 1 where b.column_1 is null and a.column_2 = 2; 76782 rows returned 选择2: select count(*) from tab
select count(*)
from table_1 a
left join table_2 b
on a.column_1 = b.column_1
and b.column_2 = 1
where b.column_1 is null
and a.column_2 = 2;
76782 rows returned
选择2:
select count(*)
from table_1 a
left join table_2 b
on a.column_1 = b.column_1
and a.column_2 = 2
and b.column_2 = 1
where b.column_1 is null;
307778 rows returned
DB版本是Oracle 12.2.0.1.0
有人能解释一下返回不同行数的两个select语句的背后是什么吗?select 1:
select count(*)
from table_1 a
where not exists (select 1
from table_2 b
where a.column_1 = b.column_1
and b.column_2 = 1)
and a.column_2 = 2;
条件b.列_2=1在左连接之前应用于表_1,
在应用所有外部联接后,将条件a.column_2=2和b.column_1为null应用于数据集。
即,查询执行以下操作:
循环遍历满足条件table_1.column_2=2的所有table_1行,然后
尝试查找满足条件table_2.column_2=1的table_2行,并将它们与列_1上的table_1左外连接,然后
筛选结果行,以便仅保留满足外部联接后条件表_2的行。列_1为空。
选择2:
select count(*)
from table_1 a
where not exists (select 1
from table_2 b
where a.column_1 = b.column_1
and b.column_2 = 1
and a.column_2 = 2);
条件b.列_2=1在左连接之前应用于表_1,
条件a.column_1=2充当连接谓词,即它表示仅当a.column_1=2时才查找匹配行,
条件b.column_1为null将在应用所有外部联接后应用于数据集。
即,查询执行以下操作:
循环遍历满足条件table_1.column_2=2的所有table_1行,然后
尝试查找满足条件table_2.column_2=1的table_2行,并将它们与列_1上的table_1进行左外连接,但仅限于满足条件table_1.column_1=2的table_1行,
筛选结果行,以便仅保留满足外部联接后条件表_2的行。列_1为空
注:
事实上,在查看查询的执行计划时,可以最好地检查幕后发生的事情,将注意力更多地集中在查询的访问/筛选谓词部分。实际上,这是一个很好的一般性建议:当您不了解所看到的查询的某些内容时,请查看其执行计划,这是一种更具命令性的语言,如。第一个过滤器使用a.column_2=2,因为它位于where子句中
第二个在a上没有过滤器。为什么?因为a.column_2=2。即使这不是真的,也会返回一行,因为这是以a作为第一个表的左联接
但是,应该发生的是,对于非2行,a中的任何列都为NULL。两个查询都在执行反联接,其中b.column_1为NULL将排除表_1中与联接条件匹配的所有行。将条件移动到联接中会使联接更具限制性,因此反联接排除的行更少
有时,我发现将反连接重新编写为不存在更直观:
选择1:
select count(*)
from table_1 a
where not exists (select 1
from table_2 b
where a.column_1 = b.column_1
and b.column_2 = 1)
and a.column_2 = 2;
选择2:
select count(*)
from table_1 a
where not exists (select 1
from table_2 b
where a.column_1 = b.column_1
and b.column_2 = 1
and a.column_2 = 2);
您可以将其改写为:
select count(*)
from table_1 a
where (a.column_2 = 2
and not exists (select 1
from table_2 b
where a.column_1 = b.column_1
and b.column_2 = 1)
)
OR a.column_2 <> 2;
这显然比Select 1限制性小得多。如果在where子句中放置左连接表的非空条件,则它将变成一个内部连接