SQL JOIN条件移动到where子句产生差异
SQL JOIN Condition moved to with where clause produces differences
查询 1
select count(1)
from sdb_snmp_sysdata s
left join sdb_snmp_entphysicaltable e on s.source = e.source **and e.class = 3**
left join SDB_DF_DEVICE_DNS dns on dns.source = s.source
left join sdb_fdb_node f on upper(f.oldnodeid) = upper(dns.dns_name)
where (regexp_like(s.descr, 'NFXS-F FANT-F ALCATEL-LUCENT|Motorola APEX3000')
or regexp_like(e.descr, 'Motorola BSR64000 HD 100A Redundant Chassis|AS2511-RJ chassis')
or trim(e.ModelName) in ('RFGW1', 'ARCT01949', 'ARCT03253', 'UBR10012', 'WS-C3750-48TS-S', 'WS-C3750V2-48TS-S')
or e.name like '%Nexus5596 Chassis%')
查询 2:
select count(1)
from sdb_snmp_sysdata s
left join sdb_snmp_entphysicaltable e on s.source = e.source
left join SDB_DF_DEVICE_DNS dns on dns.source = s.source
left join sdb_fdb_node f on upper(f.oldnodeid) = upper(dns.dns_name)
where (regexp_like(s.descr, 'NFXS-F FANT-F ALCATEL-LUCENT|Motorola APEX3000')
or regexp_like(e.descr, 'Motorola BSR64000 HD 100A Redundant Chassis|AS2511-RJ chassis')
or trim(e.ModelName) in ('RFGW1', 'ARCT01949', 'ARCT03253', 'UBR10012', 'WS-C3750-48TS-S', 'WS-C3750V2-48TS-S')
or e.name like '%Nexus5596 Chassis%') **and e.class = 3**
以上两个通过改变e.class condition from on clause to where clause
查询return不同的行数。我想不通。任何帮助表示赞赏。
我的理解:
sysdata 和 entphysicaltable 散列连接之间的查询 1 左外连接发生在对单个表进行全面扫描之后。
在第二个查询中,在 entphysicaltable 减少为仅包含 entphysicaltable.class = 3 的记录之后发生连接。
对我来说,查询的意义相同,但 return 的结果不同。
我能理解这个question我想知道一个具体的原因。
如果我没看错你的问题,那么它只是简单地归结为 LEFT JOIN 的工作原理。
(外部)LEFT JOIN 的工作方式是它将左侧的内容与右侧的内容连接起来。
然后它是一个外部连接,它会尝试向右侧添加 NULL 值,以应对右侧没有匹配项的情况。
但是,通过在 WHERE 子句中添加约束,您是在告诉查询引擎过滤掉包含 NULL 的行,因为它们与您的 WHERE 子句不匹配。
如果您的 ON 子句中有过滤器 - 查询引擎将不会 remove/filter 出 NULL 行。
发生这种情况是因为 WHERE 在 JOIN 之后是 'executed'。
这就是您获得不同行数的原因,因为根据您使用的是 ON 子句还是 WHERE 子句,OUTER 联接的功能不同。
因此,如果您希望连接包含 NULL 行,则需要使用 ON 子句。
最好的解释是一个小例子。让我们有两个表
TABLE A
C1
----------
1
2
TABLE B
C1 C2
---------- -
1 x
然后在 ON 子句中使用过滤器 B.c2 = 'x'
进行查询 returns 2 行
select *
from A left outer join B
on A.c1 = B.c1 and B.c2 = 'x';
C1 C1 C2
---------- ---------- --
1 1 x
2
而在 WHERE 子句中移动过滤器时,仅传递一行
select *
from A left outer join B
on A.c1 = B.c1
WHERE B.c2 = 'x';
C1 C1 C2
---------- ---------- --
1 1 x
WHERE 子句简单地否决了 OUTER JOIN 行缺少逻辑 - 我们都知道 NULL 不等于 'x',因此第二行被丢弃。
BWT 如果您在 旧连接语法中看到 结构,例如 B.c2(+) = 'x'
这是完全相同的 thema。
查询 1
select count(1)
from sdb_snmp_sysdata s
left join sdb_snmp_entphysicaltable e on s.source = e.source **and e.class = 3**
left join SDB_DF_DEVICE_DNS dns on dns.source = s.source
left join sdb_fdb_node f on upper(f.oldnodeid) = upper(dns.dns_name)
where (regexp_like(s.descr, 'NFXS-F FANT-F ALCATEL-LUCENT|Motorola APEX3000')
or regexp_like(e.descr, 'Motorola BSR64000 HD 100A Redundant Chassis|AS2511-RJ chassis')
or trim(e.ModelName) in ('RFGW1', 'ARCT01949', 'ARCT03253', 'UBR10012', 'WS-C3750-48TS-S', 'WS-C3750V2-48TS-S')
or e.name like '%Nexus5596 Chassis%')
查询 2:
select count(1)
from sdb_snmp_sysdata s
left join sdb_snmp_entphysicaltable e on s.source = e.source
left join SDB_DF_DEVICE_DNS dns on dns.source = s.source
left join sdb_fdb_node f on upper(f.oldnodeid) = upper(dns.dns_name)
where (regexp_like(s.descr, 'NFXS-F FANT-F ALCATEL-LUCENT|Motorola APEX3000')
or regexp_like(e.descr, 'Motorola BSR64000 HD 100A Redundant Chassis|AS2511-RJ chassis')
or trim(e.ModelName) in ('RFGW1', 'ARCT01949', 'ARCT03253', 'UBR10012', 'WS-C3750-48TS-S', 'WS-C3750V2-48TS-S')
or e.name like '%Nexus5596 Chassis%') **and e.class = 3**
以上两个通过改变e.class condition from on clause to where clause
查询return不同的行数。我想不通。任何帮助表示赞赏。
我的理解: sysdata 和 entphysicaltable 散列连接之间的查询 1 左外连接发生在对单个表进行全面扫描之后。 在第二个查询中,在 entphysicaltable 减少为仅包含 entphysicaltable.class = 3 的记录之后发生连接。
对我来说,查询的意义相同,但 return 的结果不同。
我能理解这个question我想知道一个具体的原因。
如果我没看错你的问题,那么它只是简单地归结为 LEFT JOIN 的工作原理。
(外部)LEFT JOIN 的工作方式是它将左侧的内容与右侧的内容连接起来。 然后它是一个外部连接,它会尝试向右侧添加 NULL 值,以应对右侧没有匹配项的情况。
但是,通过在 WHERE 子句中添加约束,您是在告诉查询引擎过滤掉包含 NULL 的行,因为它们与您的 WHERE 子句不匹配。 如果您的 ON 子句中有过滤器 - 查询引擎将不会 remove/filter 出 NULL 行。 发生这种情况是因为 WHERE 在 JOIN 之后是 'executed'。
这就是您获得不同行数的原因,因为根据您使用的是 ON 子句还是 WHERE 子句,OUTER 联接的功能不同。 因此,如果您希望连接包含 NULL 行,则需要使用 ON 子句。
最好的解释是一个小例子。让我们有两个表
TABLE A
C1
----------
1
2
TABLE B
C1 C2
---------- -
1 x
然后在 ON 子句中使用过滤器 B.c2 = 'x'
进行查询 returns 2 行
select *
from A left outer join B
on A.c1 = B.c1 and B.c2 = 'x';
C1 C1 C2
---------- ---------- --
1 1 x
2
而在 WHERE 子句中移动过滤器时,仅传递一行
select *
from A left outer join B
on A.c1 = B.c1
WHERE B.c2 = 'x';
C1 C1 C2
---------- ---------- --
1 1 x
WHERE 子句简单地否决了 OUTER JOIN 行缺少逻辑 - 我们都知道 NULL 不等于 'x',因此第二行被丢弃。
BWT 如果您在 旧连接语法中看到 结构,例如 B.c2(+) = 'x'
这是完全相同的 thema。