Семантическая разница между запросами на соединение - PullRequest
3 голосов
/ 09 сентября 2010

У меня есть два запроса, которые, по моему мнению, означают одно и то же, но я продолжаю получать разные результаты, и я надеялся, что кто-то сможет объяснить, как они отличаются:

1

select * 
from table1 a 
left join table2 b on a.Id = b.Id and a.val = 0
where b.Id is null

2

select * 
from table1 a 
left join table2 b on a.Id = b.Id 
where b.Id is null 
    and a.val = 0

Смысл запроса - найти строки, которые находятся в table1 и val = 0, которых нет в table2.

Я также использую sql server 2008, но сомневаюсь, что это должно иметь значение.

Ответы [ 3 ]

9 голосов
/ 09 сентября 2010

При рассмотрении левых объединений думайте о них как о трех концептуальных этапах.

  1. Применяется фильтр объединения
  2. Левые строки добавляются обратно в
  3. где применяется условие.

Затем вы увидите, почему вы получаете разные результаты.

Это также объясняет, почему это возвращает результаты

select o.* 
from sys.objects o
left join sys.objects o2 on o.object_id=o2.object_id and 1=0

И это не 'т.

select o.* 
from sys.objects o
left join sys.objects o2 on o.object_id=o2.object_id 
where 1=0
1 голос
/ 09 сентября 2010

Если вы полностью удалите предложение WHERE, использование LEFT OUTER JOIN означает, что появятся все строки таблицы слева, даже если они не удовлетворяют критериям JOIN. Например, ни одна строка не удовлетворяет выражению 1 = 0, однако это:

SELECT * 
  FROM table1 AS a 
       LEFT OUTER JOIN table2 AS b 
          ON a.Id = b.Id
             AND 1 = 0;

все еще приводит к тому, что все строки в таблице1 возвращаются там, где совпадают значения id. Проще говоря, так работает OUTER JOIN с.

Предложение WHERE применяется после JOIN, поэтому это

SELECT * 
  FROM table1 AS a 
       LEFT OUTER JOIN table2 AS b 
          ON a.Id = b.Id
 WHERE 1 = 0;

не вернет никаких строк.

1 голос
/ 09 сентября 2010
  SELECT * from TABLE1 t1
  WHERE Val = 0
  AND NOT EXISTS(SELEct 1 from Table2 t2 Where t1.Id = t2.Id)
...