2015-12-18 3 views
0

Query 1SQL JOIN Condition переехал с тем, где пункт производит различия

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. Я не могу понять. любая помощь приветствуется.

Мое понимание: запрос 1 левое внешнее соединение между sysdata и entphysicaltable hash join происходит после полного сканирования отдельных таблиц. во втором запросе 2 соединение происходит после того, как entphysicaltable сводится к записям, содержащим только entphysicaltable.class = 3.

для меня запрос имеет тот же смысл, но возвращает разные результаты.

Я могу связать это question Я хотел бы знать конкретную причину.

+0

Где вы перемещаете предикат 'e.class = 3' из' ON' в 'WHERE', LEFT JOIN' преобразуется в' INNER JOIN'. Вы должны сделать это как 'WHERE (e.class = 3 ИЛИ e.class IS NULL) ...', если вы хотите, чтобы он был эквивалентным. –

ответ

2

Наилучшее объяснение находится на небольшом примере. Пусть есть две таблицы

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

TABLE B   

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

Затем запрос с фильтром B.c2 = 'x' в предложении ON возвращает 2 строки

select * 
from A left outer join B 
on A.c1 = B.c1 and B.c2 = 'x'; 

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

в то время, когда фильтр перемещается в ИНЕКЕ, только одна строка поставляется

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', это те же самые темы.

2

Если я правильно прочитал ваш вопрос, то это просто сводится к тому, как работает LEFT JOIN.

Способ работы (внешний) LEFT JOIN заключается в том, что он присоединится к тому, что находится слева от того, что находится на вашей правой стороне. И затем, будучи внешним соединением, он попытается добавить значения NULL вправо, в ситуации, когда справа нет совпадений.

Однако, добавляя свои ограничения в предложение WHERE, вы указываете механизму запросов на фильтрацию строк, где есть NULL, потому что они не будут соответствовать вашему предложению WHERE. Если у вас есть фильтры в предложении ON, механизм запроса не удалит/не отфильтрует строки NULL. Это происходит потому, что WHERE «выполняется» после JOIN.

Вот почему вы получаете различное количество строк, потому что соединение OUTER работает по-разному в зависимости от того, используете ли вы предложение ON или WHERE. Итак, если вы хотите, чтобы соединение включало NULL-строки, вам нужно использовать предложение ON.