Oracle оставил внешнее соединение с нулевым значением в условии JOIN vs WHERE (пример)

Я не могу понять, почему Oracle возвращает эти странные результаты. Я думаю, что код действительно очень ясен.

Я ожидал, что нет условия = (НЕ является нулевым в OUTER JOIN cond) + (нуль в OUTER JOIN cond)

Поскольку я интерпретирую 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  

person Revious    schedule 19.06.2013    source источник


Ответы (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 строки из основных таблиц не имеют соответствующих идентификаторов в объединенной таблице.


Когда вы помещаете условие в предложение OUTER JOIN, вы говорите Oracle OUTER JOIN преобразовать вашу основную таблицу в подмножество строк из объединенной таблицы.

Поскольку c.flh_stato никогда не бывает нулевым, условие является избыточным, и мы получаем тот же результат, что и запрос без условий:

No condition                             6403
is NOT null in OUTER JOIN cond           6403

С условием c.flh_stato IS NULL в предложении соединения мы присоединяем основную таблицу к пустому набору результатов, таким образом, мы получаем одну строку для каждой строки основной таблицы (мы вычитаем, что основная таблица имеет 6247 строк с этим условием):

is null in OUTER JOIN cond               6247
person Vincent Malgrat    schedule 19.06.2013
comment
Действительно очень хорошо знать. Даже если я думаю, что оракул странный... Зачем разрешать предварительную фильтрацию таблиц в условии JOIN.. это странно.. Я думал использовать в условиях JOIN только условие соединения и, возможно, эквивалент EXIST/NOT EXIST.. не предварительный фильтр ... - person Revious; 19.06.2013
comment
@ Gik25 Я не уверен, что это относится к Oracle. Похоже, это прямое применение синтаксиса SQL. Посмотрите, как эти примеры ведут себя аналогично в MySQL, MS SQL. Чаще всего анти-объединение с NOT IN или NOT EXISTS проще для понимания и имеет те же параметры оптимизатора в Oracle (однако остерегайтесь нулей). - person Vincent Malgrat; 20.06.2013