Aide avec un WHERE sur une requête SQL JOINDRE GAUCHE
Question
J'essaie de créer 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. Il est facile de savoir si un utilisateur a téléchargé un document spécifique . mais je dois générer une requête dont les résultats ressemblent à ceci:
name id
----------------------
abc NULL
bbb 2
ccc 53
ddd NULL
eee 13
L'identifiant n'est pas vraiment important; Ce qui m'intéresse, c'est de savoir si le document a été téléchargé (est-il nul ou non).
Voici ma requête:
SELECT Documents.name, HasDownloaded.id FROM Documents
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id
WHERE HasDownloaded.memberID = @memberID
Le problème est que cela ne retournera des valeurs que s'il existe une entrée pour l'utilisateur spécifié dans la table HasDownloaded. J'aimerais que cela reste simple et que seules les entrées HasDownloaded soient entrées pour les documents ayant été téléchargés . 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, avec simplement l'id en tant que NULL. Mais la clause WHERE ne me donne que les valeurs pour lesquelles des entrées existent.
Je ne suis pas vraiment un expert en SQL - existe-t-il un opérateur qui me donnera ce que je veux ici? Devrais-je adopter une approche différente? Ou est-ce impossible?
La solution
Déplacez la condition de la clause WHERE vers la condition de jointure.
SELECT Documents.name, HasDownloaded.id FROM Documents
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id
AND HasDownloaded.memberID = @memberID
Cela est nécessaire chaque fois que vous souhaitez faire référence à une table jointe de gauche dans ce qui serait autrement la clause WHERE.
Autres conseils
WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId
serait la manière normale de le faire. Certains voudraient le raccourcir à:
WHERE COALESCE(HasDownloaded.memberId, @memberId) = @memberId
Vous pouvez, comme le montre Matt B., le faire dans votre condition JOIN - mais je pense que cela est beaucoup plus susceptible de confondre les gens. Si vous ne comprenez pas pourquoi le passage à la clause JOIN fonctionne, alors je vous suggère fortement de vous en éloigner.
@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 fait un test rapide (c’était plutôt simpliste, je pense, sur seulement 14 lignes et 10 essais):
Dans la condition JOIN:
AND HasDownloaded.memberID = @memberID
- Temps de traitement du client: 4.6
- Durée totale d'exécution: 35.5
- Temps d'attente pour les réponses du serveur: 30.9
Dans la clause WHERE:
WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId
- Temps de traitement du client: 7.7
- Durée totale d'exécution: 27,7
- Temps d'attente pour les réponses du serveur: 22.0
Il semble que la clause WHERE soit légèrement plus efficace. Intéressant! Encore une fois, merci à vous deux pour votre aide.