Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

SQL selecione onde não está na subconsulta não retorna resultados


Atualização:

Estes artigos no meu blog descrevem as diferenças entre os métodos com mais detalhes:
  • NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL :SQL Server
  • NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL :PostgreSQL
  • NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL :Oracle
  • NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL :MySQL

Existem três maneiras de fazer essa consulta:

  • LEFT JOIN / IS NULL :
    SELECT  *
    FROM    common
    LEFT JOIN
            table1 t1
    ON      t1.common_id = common.common_id
    WHERE   t1.common_id IS NULL
    

  • NOT EXISTS :
    SELECT  *
    FROM    common
    WHERE   NOT EXISTS
            (
            SELECT  NULL
            FROM    table1 t1
            WHERE   t1.common_id = common.common_id
            )
    

  • NOT IN :
    SELECT  *
    FROM    common
    WHERE   common_id NOT IN
            (
            SELECT  common_id
            FROM    table1 t1
            )
    

Quando table1.common_id não é anulável, todas essas consultas são semanticamente iguais.

Quando é anulável, NOT IN é diferente, pois IN (e, portanto, NOT IN ) return NULL quando um valor não corresponde a nada em uma lista contendo um NULL .

Isso pode ser confuso, mas pode se tornar mais óbvio se lembrarmos a sintaxe alternativa para isso:
common_id = ANY
(
SELECT  common_id
FROM    table1 t1
)

O resultado desta condição é um produto booleano de todas as comparações dentro da lista. Claro, um único NULL valor produz o NULL resultado que renderiza todo o resultado NULL também.

Nunca podemos dizer com certeza que common_id não é igual a nada desta lista, pois pelo menos um dos valores é NULL .

Suponha que temos estes dados:
common

--
1
3

table1

--
NULL
1
2

LEFT JOIN / IS NULL e NOT EXISTS retornará 3 , NOT IN retornará nada (já que sempre será avaliado como FALSE ou NULL ).

Em MySQL , no caso de coluna não anulável, LEFT JOIN / IS NULL e NOT IN são um pouco (vários por cento) mais eficientes que NOT EXISTS . Se a coluna for anulável, NOT EXISTS é o mais eficiente (novamente, não muito).

Em Oracle , todas as três consultas geram os mesmos planos (um ANTI JOIN ).

Em SQL Server , NOT IN / NOT EXISTS são mais eficientes, pois LEFT JOIN / IS NULL não pode ser otimizado para um ANTI JOIN pelo seu otimizador.

Em PostgreSQL , LEFT JOIN / IS NULL e NOT EXISTS são mais eficientes que NOT IN , pois são otimizados para um Anti Join , enquanto NOT IN usa hashed subplan (ou mesmo um simples subplan se a subconsulta for muito grande para hash)