SQL “выбор, куда не в подзапросе” не возвращает результатов

Оба реализуют те же интерфейсы, таким образом, они будут вести себя тот же путь. Возможно, они реализованы по-другому внутренне, но это должно было бы быть протестировано.

единственными реальными различиями, которые я вижу, являются пространства имен и то, которое Collection<T> отмечено с ComVisibleAttribute(false), таким образом, код COM не может использовать его.

120
задан Jeremy Stein 19 February 2014 в 17:52
поделиться

7 ответов

Обновление:

Эти статьи в моем блоге более подробно описывают различия между методами:


Есть три способа выполнить такой запрос:

  • LEFT JOIN / IS NULL :

     ВЫБРАТЬ *
    ИЗ общего
    LEFT JOIN
     table1 t1
    ВКЛ t1.common_id = common.common_id
    ГДЕ t1.common_id ЕСТЬ NULL
    
  • НЕ СУЩЕСТВУЕТ :

     ВЫБРАТЬ *
    ИЗ общего
    ГДЕ НЕ СУЩЕСТВУЕТ
     (
     ВЫБРАТЬ NULL
     ИЗ table1 t1
     ГДЕ t1.common_id = common.common_id
     )
    
  • НЕ В :

     ВЫБРАТЬ *
    ИЗ общего
    ГДЕ common_id НЕ В
     (
     ВЫБЕРИТЕ common_id
     ИЗ table1 t1
     )
    

Когда table1.common_id не допускает значения NULL, все эти запросы семантически одинаковы.

Когда он допускает значение NULL, NOT IN отличается, поскольку IN (и, следовательно, NOT IN ) возвращает NULL , когда значение не соответствует ничему в списке, содержащем NULL . ​​

Это может быть сбивает с толку, но может стать более очевидным, если мы вспомним альтернативный синтаксис для этого:

common_id = ANY
(
SELECT  common_id
FROM    table1 t1
)

Результатом этого условия является логическое произведение всех сравнений в списке. Конечно, одно значение NULL дает результат NULL , который также отображает весь результат NULL .

Мы никогда не можем точно сказать, что common_id не соответствует чему-либо из этого списка, поскольку по крайней мере одно из значений NULL .

Предположим, у нас есть следующие данные:

common

--
1
3

table1

--
NULL
1
2

LEFT JOIN / IS NULL и NOT EXISTS вернет 3 , NOT IN вернет ничего (так как всегда будет оцениваться как FALSE или NULL ).

В MySQL в случае столбца, не допускающего значения NULL, LEFT JOIN / IS NULL и NOT IN немного (на несколько процентов) более эффективны, чем НЕ СУЩЕСТВУЕТ . Если столбец допускает значение NULL, NOT EXISTS является наиболее эффективным (опять же, не очень).

В Oracle все три запроса дают одинаковые планы ( ANTI JOIN ).

В SQL Server ,

218
ответ дан 24 November 2019 в 01:37
поделиться

Если вы хотите, чтобы мир был двузначным логическим местом, вы должны сами предотвратить случай null (третье значение).

Не пишите предложения IN, которые разрешают нули в сторона списка. Отфильтруйте их!

common_id not in
(
  select common_id from Table1
  where common_id is not null
)
35
ответ дан 24 November 2019 в 01:37
поделиться
SELECT T.common_id
  FROM Common T
       LEFT JOIN Table1 T1 ON T.common_id = T1.common_id
       LEFT JOIN Table2 T2 ON T.common_id = T2.common_id
 WHERE T1.common_id IS NULL
   AND T2.common_id IS NULL
3
ответ дан 24 November 2019 в 01:37
поделиться

Таблица1 или Таблица2 имеет несколько нулевых значений для common_id. Вместо этого используйте этот запрос:

select *
from Common
where common_id not in (select common_id from Table1 where common_id is not null)
and common_id not in (select common_id from Table2 where common_id is not null)
5
ответ дан 24 November 2019 в 01:37
поделиться
select *
from Common c
where not exists (select t1.commonid from table1 t1 where t1.commonid = c.commonid)
and not exists (select t2.commonid from table2 t2 where t2.commonid = c.commonid)
4
ответ дан 24 November 2019 в 01:37
поделиться

Просто в голове ...

select c.commonID, t1.commonID, t2.commonID
from Common c
     left outer join Table1 t1 on t1.commonID = c.commonID
     left outer join Table2 t2 on t2.commonID = c.commonID
where t1.commonID is null 
     and t2.commonID is null

Я провел несколько тестов, и вот мои результаты по ответу @ patmortech и комментариям @rexem.

Если либо Table1, либо Table2 не индексируется по commonID, вы получаете сканирование таблицы, но запрос @patmortech по-прежнему в два раза быстрее (для главной таблицы со 100K строками).

Если ни одна из них не проиндексирована по commonID, вы получаете два сканирования таблицы, и разница незначительна.

Если оба индексируются по commonID, запрос «не существует» выполняется в 1/3 времени.

3
ответ дан 24 November 2019 в 01:37
поделиться

Let's suppose these values for common_id:

Common - 1
Table1 - 2
Table2 - 3, null

We want the row in Common to return, because it doesn't exist in any of the other tables. However, the null throws in a monkey wrench.

With those values, the query is equivalent to:

select *
from Common
where 1 not in (2)
and 1 not in (3, null)

That is equivalent to:

select *
from Common
where not (1=2)
and not (1=3 or 1=null)

This is where the problem starts. When comparing with a null, the answer is unknown. So the query reduces to

select *
from Common
where not (false)
and not (false or unkown)

false or unknown is unknown:

select *
from Common
where true
and not (unknown)

true and not unkown is also unkown:

select *
from Common
where unknown

The where condition does not return records where the result is unkown, so we get no records back.

One way to deal with this is to use the exists operator rather than in. Exists never returns unkown because it operates on rows rather than columns. (A row either exists or it doesn't; none of this null ambiguity at the row level!)

select *
from Common
where not exists (select common_id from Table1 where common_id = Common.common_id)
and not exists (select common_id from Table2 where common_id = Common.common_id)
3
ответ дан 24 November 2019 в 01:37
поделиться