Oracle left outer join with is null in JOIN vs WHERE 条件(示例)

Posted

技术标签:

【中文标题】Oracle left outer join with is null in JOIN vs WHERE 条件(示例)【英文标题】:Oracle left outer join with is null in JOIN vs WHERE condition (example) 【发布时间】:2013-06-19 13:29:55 【问题描述】:

我无法理解 Oracle 返回这个奇怪结果的原因。 我认为代码真的很清楚。

我期待 无条件 = (在 OUTER JOIN 条件下不为空) + (在 OUTER JOIN 条件下为空)

因为我将外部连接右表列中的 IS NULL / IS NOT NULL 解释为 EXISTS / NOT EXISTS 条件。

为什么我错了?

DESCRIPTION                          COUNT(1)
---------------------------------- ----------
No condition                             6403
is NOT null in OUTER JOIN cond           6403
is not null in where cond                6401
is null in OUTER JOIN cond               6247
is null in where cond                       2
proof flh_id_messaggio is not null          0
proof flh_stato is not null                 0


  SELECT 'is null in OUTER JOIN cond ' description, count(1)
    FROM    netatemp.TMP_BACKLOG_NOBILLING2013 t
         LEFT OUTER JOIN
            eni_flussi_hub c ON
            c.flh_id_messaggio = t.flh_id_messaggio  
            AND c.flh_stato is null   
   WHERE 1 = 1 
       And t.flh_stato = 'PA'
         AND t.OWNER = 'ETL' 
UNION
  SELECT 'is NOT null in OUTER JOIN cond ' description, count(1)
    FROM    netatemp.TMP_BACKLOG_NOBILLING2013 t
         LEFT OUTER JOIN
            eni_flussi_hub c ON
            c.flh_id_messaggio = t.flh_id_messaggio  
            AND c.flh_stato is not null   
   WHERE 1 = 1 
       And t.flh_stato = 'PA'
         AND t.OWNER = 'ETL'
UNION
  SELECT 'is null in where cond ' description, count(1)
    FROM    netatemp.TMP_BACKLOG_NOBILLING2013 t
         LEFT OUTER JOIN
            eni_flussi_hub c ON
            c.flh_id_messaggio = t.flh_id_messaggio                
   WHERE 1 = 1 
       And t.flh_stato = 'PA'
         AND t.OWNER = 'ETL'
         AND c.flh_stato is null 
UNION
  SELECT 'is not null in where cond ' description, count(1)
    FROM    netatemp.TMP_BACKLOG_NOBILLING2013 t
         LEFT OUTER JOIN
            eni_flussi_hub c ON
            c.flh_id_messaggio = t.flh_id_messaggio                
   WHERE 1 = 1 
       And t.flh_stato = 'PA'
         AND t.OWNER = 'ETL'
         AND c.flh_stato is not null 
UNION
  SELECT 'No condition' description, count(1)
    FROM    netatemp.TMP_BACKLOG_NOBILLING2013 t
         LEFT OUTER JOIN
            eni_flussi_hub c ON
            c.flh_id_messaggio = t.flh_id_messaggio                
   WHERE 1 = 1 
       And t.flh_stato = 'PA'
         AND t.OWNER = 'ETL'
UNION select 'proof flh_stato is not null' description, count(1)
from eni_flussi_hub
where flh_stato is null         
UNION select 'proof flh_id_messaggio is not null' description, count(1)
from eni_flussi_hub
where flh_id_messaggio is null  

【问题讨论】:

【参考方案1】:

EXISTS/NOT EXISTS 等效查询是通过将NULL 条件放在WHERE 子句而不是OUTER JOIN 子句中获得的。顺便说一句,这是我们从您的结果中观察到的:

No condition                             6403
is not null in where cond                6401
is null in where cond                       2

主表中的 2 行在连接表中没有对应的 ID。


当您将条件放在OUTER JOIN 子句中时,您是在告诉Oracle 将OUTER JOIN 您的主表添加到连接表中的行子集

由于c.flh_stato 永远不会为空,因此条件是多余的,我们得到的结果与无条件查询相同:

No condition                             6403
is NOT null in OUTER JOIN cond           6403

使用join子句中的条件c.flh_stato IS NULL,我们将主表连接到一个空的结果集,因此我们得到主表每一行的一行(我们用这个条件推导出主表有6247行):

is null in OUTER JOIN cond               6247

【讨论】:

真的很高兴知道。即使我认为 oracle 很奇怪......为什么允许在 JOIN 条件中预过滤表......这很奇怪......我想在 JOIN 条件中使用连接条件,也许是 EXIST / NOT EXIST 等价......不是预过滤器... @Gik25 我不确定这是特定于 Oracle 的。这似乎是 SQL 合成器的直接应用。请参阅mysql、MS SQL 中的这些示例。大多数情况下,NOT INNOT EXISTS 的反连接更容易理解,并且在 Oracle 中具有相同的优化器选项(但要注意空值)。

以上是关于Oracle left outer join with is null in JOIN vs WHERE 条件(示例)的主要内容,如果未能解决你的问题,请参考以下文章

“,”“natural join”“natural left outer join”“natural right outer join”的用法总结

Left Outer Join 的条件谓词评估较晚,导致性能问题。甲骨文 8i

关于mysql中的left join和left outer join的区别

MySQL 数据库中 left outer join 和 left join 啥区别

Oracle left join 或right join

MySQL 数据库中 left outer join 和 left join 啥区别?