Ajuda com um WHERE em um LEFT JOIN SQL Query
Pergunta
Eu estou tentando construir uma consulta que irá incluir uma coluna que indica se ou não um usuário tenha baixado um documento. Eu tenho uma tabela chamada HasDownloaded com as seguintes colunas: id, documentID, memberID. Descobrir se um usuário tiver baixado um específica documento é fácil; mas eu preciso gerar uma consulta onde os resultados será parecido com este:
name id
----------------------
abc NULL
bbb 2
ccc 53
ddd NULL
eee 13
A ID não é realmente importante; o que me interessa é se o documento já foi baixado (é NULL ou não).
Aqui está minha consulta:
SELECT Documents.name, HasDownloaded.id FROM Documents
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id
WHERE HasDownloaded.memberID = @memberID
O problema é que isto só irá retornar valores se existe uma entrada para o usuário especificado na tabela de HasDownloaded. Eu gostaria de manter este simples e só tem entradas no HasDownloaded para documentos que Tem foi baixado. Assim, se o usuário 1 tem baixado abc, bbb, e ccc, eu ainda quero ddd e eee a mostrar-se na tabela resultante, apenas com o ID como NULL. Mas a cláusula WHERE só me dá valores para os quais existe entradas.
Eu não sou muito de um especialista em SQL - existe um operador que vai me dar o que eu quero aqui? Eu deveria estar tomando uma abordagem diferente? Ou isso é impossível?
Solução
Mover a condição na cláusula WHERE à condição de junção.
SELECT Documents.name, HasDownloaded.id FROM Documents
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id
AND HasDownloaded.memberID = @memberID
Isto é necessário sempre que você quer para se referir a uma esquerda juntar-ed mesa no que de outra forma seria a cláusula WHERE.
Outras dicas
WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId
seria a maneira normal de fazer isso. Alguns poderiam encurtar a:
WHERE COALESCE(HasDownloaded.memberId, @memberId) = @memberId
Você pode, como Matt B. mostra, fazê-lo em sua condição JOIN - mas eu acho que é muito mais provável que as pessoas Confuse. Se você não entender por que movê-lo para o JOIN obras cláusula, então eu fortemente sugiro ficar longe dela.
@ Marcos: Eu entendo por que o JOIN sintaxe funciona, mas obrigado pelo aviso. Eu acho que sua sugestão é mais intuitivo. Eu estava curioso para ver o que era mais eficiente. Então eu corri um teste rápido (isso foi bastante simplista, eu estou com medo, mais de apenas 14 linhas e 10 ensaios):
Na condição de junção:
AND HasDownloaded.memberID = @memberID
- tempo de processamento do cliente: 4.6
- Total de tempo de execução: 35,5
- tempo de espera nas respostas do servidor: 30,9
Na cláusula WHERE:
WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId
- tempo de processamento do cliente: 7.7
- Total de tempo de execução: 27,7
- tempo de espera nas respostas do servidor: 22,0
Parece que a cláusula WHERE é sempre tão ligeiramente mais eficiente. Interessante! Mais uma vez, graças a ambos por sua ajuda.