Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

SQL select where not in subquery ne renvoie aucun résultat

Mise à jour :

Ces articles de mon blog décrivent plus en détail les différences entre les méthodes :

  • 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

Il existe trois façons de faire une telle requête :

  • 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
            )
    

Lorsque table1.common_id n'accepte pas la valeur null, toutes ces requêtes sont sémantiquement identiques.

Lorsqu'il est nullable, NOT IN est différent, puisque IN (et, par conséquent, NOT IN ) renvoie NULL lorsqu'une valeur ne correspond à rien dans une liste contenant un NULL .

Cela peut prêter à confusion mais peut devenir plus évident si nous rappelons la syntaxe alternative pour ceci :

common_id = ANY
(
SELECT  common_id
FROM    table1 t1
)

Le résultat de cette condition est un produit booléen de toutes les comparaisons de la liste. Bien sûr, un seul NULL la valeur donne le NULL result qui rend le résultat entier NULL aussi.

Nous ne pouvons jamais dire avec certitude que common_id n'est égal à aucun élément de cette liste, car au moins une des valeurs est NULL .

Supposons que nous ayons ces données :

common

--
1
3

table1

--
NULL
1
2

LEFT JOIN / IS NULL et NOT EXISTS renverra 3 , NOT IN ne renverra rien (car il évaluera toujours soit FALSE ou NULL ).

En MySQL , dans le cas d'une colonne non nullable, LEFT JOIN / IS NULL et NOT IN sont un peu (plusieurs pour cent) plus efficaces que NOT EXISTS . Si la colonne est nullable, NOT EXISTS est le plus efficace (encore une fois, pas beaucoup).

Dans Oracle , les trois requêtes donnent les mêmes plans (un ANTI JOIN ).

Dans SQL Server , NOT IN / NOT EXISTS sont plus efficaces, puisque LEFT JOIN / IS NULL ne peut pas être optimisé pour un ANTI JOIN par son optimiseur.

Dans PostgreSQL , LEFT JOIN / IS NULL et NOT EXISTS sont plus efficaces que NOT IN , puisqu'ils sont optimisés pour un Anti Join , tandis que NOT IN utilise hashed subplan (ou même un simple subplan si la sous-requête est trop grande pour être hachée)