2008-10-20 13 views
17

Je tente de construire une requête qui inclura une colonne indiquant si un utilisateur a téléchargé un document ou non. J'ai une table appelée HasDownloaded avec les colonnes suivantes: id, documentID, memberID. Savoir si un utilisateur a téléchargé un document spécifique est facile; mais j'ai besoin de générer une requête où les résultats ressembleront à ceci:Aide avec un WHERE sur une requête SQL LEFT JOIN

name    id 
---------------------- 
abc    NULL 
bbb    2 
ccc    53 
ddd    NULL 
eee    13 

L'ID n'est pas vraiment important; ce qui m'intéresse c'est de savoir si le document a été téléchargé (est-il NULL ou non).

Voici ma question:

SELECT Documents.name, HasDownloaded.id FROM Documents 
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id 
WHERE HasDownloaded.memberID = @memberID 

Le problème est, cela ne des valeurs que si une entrée existe pour l'utilisateur spécifié dans le tableau HasDownloaded. Je voudrais garder cela simple et seulement avoir des entrées dans HasDownloaded pour les documents que ont téléchargé. Donc, si l'utilisateur 1 a téléchargé abc, bbb et ccc, je veux toujours que ddd et eee apparaissent dans la table résultante, juste avec l'id comme NULL. Mais la clause WHERE ne me donne que des valeurs pour lesquelles des entrées existent.

Je ne suis pas un expert SQL - y a-t-il un opérateur qui me donnera ce que je veux ici? Devrais-je adopter une approche différente? Ou est-ce impossible?

Répondre

35

Déplacez la condition dans la clause WHERE vers la condition de jointure. Ceci est nécessaire lorsque vous voulez faire référence à une table jointe à gauche dans ce qui serait autrement la clause WHERE.

+1

Excellent! C'est ce que je cherchais. – ine

+1

EDIT: J'ai répondu à ma propre question. J'ai été capable de trouver une bonne explication de pourquoi c'est vrai. http://weblogs.sqlteam.com/jeffs/archive/2007/05/14/criteria-on-outer-joined-tables.aspx –

4
WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId 

serait le moyen normal de le faire. Certains raccourcirait à:

WHERE COALESCE(HasDownloaded.memberId, @memberId) = @memberId 

Vous pouvez, comme Matt B. montre, faites-le dans votre condition join - mais je pense que c'est beaucoup plus susceptible de confondre les gens. Si vous ne comprenez pas POURQUOI le déplacer vers la clause JOIN fonctionne, alors je vous suggère fortement de rester loin de cela.

3

@Mark: Je comprends pourquoi la syntaxe JOIN fonctionne, mais merci pour l'avertissement. Je pense que votre suggestion est plus intuitive. J'étais curieux de voir lequel était le plus efficace. Alors j'ai couru un test rapide (ce qui est assez simpliste, je le crains, sur seulement 14 lignes et 10 essais):

Dans la condition JOIN:

AND HasDownloaded.memberID = @memberID 
  • temps de traitement du client: 4.6
  • temps total d'exécution: 35,5
  • temps d'attente sur le serveur répond: 30,9

Dans la clause WHERE:

WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId 
  • temps de traitement du client: 7,7
  • Temps total d'exécution: 27,7
  • Temps d'attente sur le serveur répond: 22.0

Il semble que la clause WHERE soit un peu plus efficace. Intéressant! Encore une fois, merci à vous deux pour votre aide.