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。