【问题标题】:Oracle left outer join with is null in JOIN vs WHERE condition (example)Oracle left outer join with is null in JOIN vs WHERE 条件(示例)
【发布时间】: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  

【问题讨论】:

    标签: oracle outer-join


    【解决方案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 IN 或 NOT EXISTS 的反连接更容易理解,并且在 Oracle 中具有相同的优化器选项(但要注意空值)。
    猜你喜欢
    • 2021-11-29
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-28
    • 2017-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多