73 votes

T-SQL : Comment sélectionner dans une liste de valeurs des valeurs qui ne sont PAS dans la table ?

J'ai une liste d'adresses e-mail, certaines d'entre elles sont dans mon tableau, d'autres non. Je veux sélectionner tous les e-mails de cette liste, qu'ils soient dans la table ou non.

Je peux obtenir les utilisateurs dont les adresses e-mail sont dans la table comme ceci :
SELECT u.* FROM USERS u WHERE u.EMAIL IN ('email1', 'email2', 'email3')

Mais comment puis-je sélectionner dans cette liste des valeurs qui n'existent pas dans la table ?

De plus, comment puis-je sélectionner comme ceci :

E-Mail | Status
email1 | Exist  
email2 | Exist  
email3 | Not Exist  
email4 | Exist  

Merci d'avance.

0 votes

Voulez-vous dire T-SQL du serveur SQL de Microsoft ? Si oui, quelle version ?

1 votes

Oui, MS SQL Server. J'utilise à la fois 2005 et 2008 R2.

0 votes

D'accord, dans ce cas, je recommande la réponse de Martin Smith. J'ai posé la question parce que même SQL Server 2000 est encore beaucoup utilisé et sa réponse ne fonctionnerait pas dans ce cas.

101voto

Martin Smith Points 174101

Pour SQL Server 2008

SELECT email,
       CASE
         WHEN EXISTS(SELECT *
                     FROM   Users U
                     WHERE  E.email = U.email) THEN 'Exist'
         ELSE 'Not Exist'
       END AS [Status]
FROM   (VALUES('email1'),
              ('email2'),
              ('email3'),
              ('email4')) E(email)  

Pour les versions précédentes, vous pouvez faire quelque chose de similaire avec un tableau dérivé UNION ALL -sur les constantes.

/*The SELECT list is the same as previously*/
FROM (
SELECT 'email1' UNION ALL
SELECT 'email2' UNION ALL
SELECT 'email3' UNION ALL
SELECT 'email4'
)  E(email)

Ou si vous ne voulez que ceux qui n'existent pas (comme l'implique le titre) plutôt que le jeu de résultats exact donné dans la question, vous pouvez simplement faire ceci

SELECT email
FROM   (VALUES('email1'),
              ('email2'),
              ('email3'),
              ('email4')) E(email)  
EXCEPT
SELECT email
FROM Users

13voto

ypercube Points 62714

Vous devez en quelque sorte créer un tableau avec ces valeurs et ensuite utiliser NOT IN . Cela peut être fait avec une table temporaire, une CTE (Common Table Expression) ou une Constructeur de valeurs de tableau (disponible dans SQL-Server 2008) :

SELECT email
FROM
    ( VALUES 
        ('email1')
      , ('email2')
      , ('email3')
    ) AS Checking (email)
WHERE email NOT IN 
      ( SELECT email 
        FROM Users
      ) 

Le deuxième résultat peut être trouvé avec un LEFT JOIN ou un EXISTS sous-requête :

SELECT email
     , CASE WHEN EXISTS ( SELECT * 
                          FROM Users u
                          WHERE u.email = Checking.email
                        ) 
            THEN 'Exists'
            ELSE 'Not exists'
       END AS status 
FROM
    ( VALUES 
        ('email1')
      , ('email2')
      , ('email3')
    ) AS Checking (email)

2voto

Lamak Points 33901

Vous devriez avoir un tableau avec la liste des emails à vérifier. Ensuite, faites cette requête :

SELECT E.Email, CASE WHEN U.Email IS NULL THEN 'Not Exists' ELSE 'Exists' END Status
FROM EmailsToCheck E
LEFT JOIN (SELECT DISTINCT Email FROM Users) U
ON E.Email = U.Email

0 votes

Merci, je ne voulais pas faire un long chemin. La réponse de Martin l'a fait.

1voto

Mark Kremers Points 720

Si vous ne voulez pas que les emails de la liste soient dans la base de données, vous pouvez faire ce qui suit :

select    u.name
        , u.EMAIL
        , a.emailadres
        , case when a.emailadres is null then 'Not exists'
               else 'Exists'
          end as 'Existence'
from      users u
          left join (          select 'email1' as emailadres
                     union all select 'email2'
                     union all select 'email3') a
            on  a.emailadres = u.EMAIL)

de cette façon, vous obtiendrez un résultat comme

name | email  | emailadres | existence
-----|--------|------------|----------
NULL | NULL   | a@b.com    | Not exists
Jan  | j@j.nl | j@j.nl     | Exists

L'utilisation des opérateurs IN ou EXISTS est plus lourde que la jointure gauche dans ce cas.

Bonne chance :)

0 votes

Merci, votre réponse est tardive mais correcte aussi. Je suis content de ne pas avoir eu à créer un tableau pour les valeurs.

2 votes

EXISTS sera plus efficace que la jointure extérieure car elle peut court-circuiter. La vôtre peut ramener la même adresse plusieurs fois s'il y a des doublons dans Users . Voir Sous-requêtes dans les expressions CASE pour obtenir des détails sur la façon dont EXISTS est traité.

0voto

Ardalan Shahgholi Points 1437

Utilisez ceci : -- SQL Server 2008 ou plus récent

SELECT U.* 
FROM USERS AS U
Inner Join (
  SELECT   
    EMail, [Status]
  FROM
    (
      Values
        ('email1', 'Exist'),
        ('email2', 'Exist'),
        ('email3', 'Not Exist'),
        ('email4', 'Exist')
    )AS TempTableName (EMail, [Status])
  Where TempTableName.EMail IN ('email1','email2','email3')
) As TMP ON U.EMail = TMP.EMail

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X