【问题标题】:SQL JOIN Condition moved to with where clause produces differencesSQL JOIN Condition 移至 where 子句产生差异
【发布时间】:2015-12-18 06:39:13
【问题描述】:

查询 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返回不同的行数。我无法弄清楚。任何帮助表示赞赏。

我的理解: sysdata 和 entphysicaltable 散列连接之间的查询 1 左外连接发生在完整扫描各个表之后。 在第二个查询中,在 entphysicaltable 减少为仅包含 entphysicaltable.class= 3 的记录之后发生了 2 连接。

对我来说,查询意义相同,但返回的结果不同。

我可以联系到这个question我想知道一个具体的原因。

【问题讨论】:

  • e.class = 3 谓词从ON 移动到WHERE 的位置,LEFT JOIN 被转换为INNER JOIN。如果你希望它是等价的,你必须让它像WHERE (e.class = 3 OR e.class IS NULL) ...

标签: sql join where


【解决方案1】:

最好的解释是一个小例子。让我们有两张桌子

TABLE A
        C1
----------
         1 
         2  

TABLE B         

        C1 C2
---------- -
         1 x

那么在ON子句中带有过滤器B.c2 = 'x'的查询返回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 如果您在 old join syntax 中看到像 B.c2(+) = 'x' 这样的构造,这就是相同的 thema。

【讨论】:

    【解决方案2】:

    如果我没看错你的问题,那么它只是归结为 LEFT JOIN 的工作原理。

    (外部)LEFT JOIN 的工作方式是将左侧的内容与右侧的内容连接起来。 然后它是一个外连接,它会尝试在右边添加 NULL 值,以应对右边没有匹配的情况。

    但是,通过在 WHERE 子句中添加约束,您是在告诉查询引擎过滤掉存在 NULL 的行,因为它们与您的 WHERE 子句不匹配。 如果您的 ON 子句中有过滤器 - 查询引擎将不会删除/过滤掉 NULL 行。 发生这种情况是因为 WHERE 在 JOIN 之后“执行”。

    这就是您获得不同行数的原因,因为根据您使用的是 ON 还是 WHERE 子句,OUTER 连接的功能会有所不同。 因此,如果您希望连接包含 NULL 行,则需要使用 ON 子句。

    【讨论】:

      猜你喜欢
      • 2011-07-13
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-28
      相关资源
      最近更新 更多