O left join não está funcionando nesse código

“Exiba agora todos os alunos e suas possíveis respostas para o exercício com ID = 1. Exiba todos os
alunos mesmo que ele não tenha respondido o exercício.
Lembre-se de usar a condição no JOIN.”

Só aparecem os que responderam, alguém pode me mostrar onde está o erro no meu código?

Segue o dump do BD:
escola.sql (7,4,KB)

O problema é que a tabela exercícios está na posição mais a direita das tabelas e você está fazendo um where pelo campo exercicio.id.

Ou seja, apenas para os alunos com uma resposta para aquele exercício, terá algum valor.

O que você pode fazer é usar um cross join entre alunos e exercicios (porque você quer sempre mostrar o exercício e o aluno, com ou sem resposta) e depois aplicar um left join com a tabela de respostas.

Algo assim:

select e.pergunta, a.nome, r.texto
from exercicios e
cross join alunos a
left join respostas r
on e.id = r.exercicio_id 
and a.id = r.aluno_id 
where e.id = 1
order by e.id, a.id

Exemplo: DB Fiddle - SQL Database Playground

1 curtida

Se o aluno não respondeu o exercício, então não terá nenhuma entrada na tabela de respostas para aquele exercício. Mas ao fazer uma busca pelo id do exercício igual a 1, você está automaticamente excluindo os que não responderam.

Além disso, a ordem das tabelas importa no LEFT JOIN. Por exemplo, se eu fizer:

SELECT r.resposta_dada, a.nome
FROM resposta r LEFT JOIN aluno a on a.id = r.aluno_id;

Ele vai trazer todos os registros da tabela resposta, e apenas os alunos que deram alguma resposta:

resposta_dada nome
uma selecao João da Silva
ixi, nao sei João da Silva
alterar dados João da Silva
eskecer o where e alterar tudo João da Silva
apagar coisas João da Silva
tb nao pode eskecer o where João da Silva
inserir dados João da Silva
buscar dados Frederico José
select campos from tabela Frederico José
alterar coisas Frederico José
ixi, nao sei Frederico José
tempo pra fazer algo Alberto Santos
1 a 4 semanas Alberto Santos
melhoria do processo Alberto Santos
todo dia Alberto Santos
reuniao de status Alberto Santos
todo dia Alberto Santos
o quadro branco Alberto Santos
um metodo agil Alberto Santos
tem varios outros Alberto Santos
eh a internet Renata Alonso
browser faz requisicao, servidor manda resposta Renata Alonso
eh o servidor que lida com http Renata Alonso
nao sei Renata Alonso
banco de dados! Renata Alonso
eh colocar a app na internet Renata Alonso
depende da tecnologia, mas geralmente eh levar pra um servidor que ta na internet Renata Alonso

Mas se eu colocar a tabela de alunos primeiro:

SELECT r.resposta_dada, a.nome
FROM aluno a LEFT JOIN resposta r on a.id = r.aluno_id;

Agora ele vai trazer todos os alunos, inclusive aqueles que não deram nenhuma resposta:

resposta_dada nome
inserir dados João da Silva
tb nao pode eskecer o where João da Silva
apagar coisas João da Silva
eskecer o where e alterar tudo João da Silva
alterar dados João da Silva
ixi, nao sei João da Silva
uma selecao João da Silva
ixi, nao sei Frederico José
alterar coisas Frederico José
select campos from tabela Frederico José
buscar dados Frederico José
tem varios outros Alberto Santos
um metodo agil Alberto Santos
o quadro branco Alberto Santos
todo dia Alberto Santos
reuniao de status Alberto Santos
todo dia Alberto Santos
melhoria do processo Alberto Santos
1 a 4 semanas Alberto Santos
tempo pra fazer algo Alberto Santos
depende da tecnologia, mas geralmente eh levar pra um servidor que ta na internet Renata Alonso
eh colocar a app na internet Renata Alonso
banco de dados! Renata Alonso
nao sei Renata Alonso
eh o servidor que lida com http Renata Alonso
browser faz requisicao, servidor manda resposta Renata Alonso
eh a internet Renata Alonso
Paulo da Silva
Carlos Cunha
Paulo José
Manoel Santos
Renata Ferreira
Paula Soares
Jose da Silva
Danilo Cunha
Zilmira José
Cristaldo Santos
Osmir Ferreira
Claudio Soares

Repare que os últimos alunos não tem resposta (são os que não deram nenhuma resposta, ou seja, não tem nenhum registro correspondente na tabela resposta). Neste caso, o resultado é NULL (mas eu coloquei como “nada” na tabela acima, pra ficar mais fácil visualizar que não tem nada).

Para mais detalhes sobre os diferentes tipos de JOIN, leia aqui.


Enfim, ao começar seu SELECT pela tabela exercicio, você já está excluindo os alunos que não deram a resposta para um exercício. Além disso, você tem que considerar os que tem id nulo, pois quando o aluno não respondeu, as colunas referentes ao exercício serão NULL. Ou seja:

SELECT e.pergunta, a.nome, r.resposta_dada
FROM aluno a
  LEFT JOIN resposta r ON a.id = r.aluno_id
  LEFT JOIN exercicio e ON e.id=r.exercicio_id
WHERE r.exercicio_id=1 OR r.exercicio_id IS NULL
ORDER BY e.id, a.id 

O resultado será:

pergunta nome resposta_dada
Paulo da Silva
Carlos Cunha
Paulo José
Manoel Santos
Renata Ferreira
Paula Soares
Jose da Silva
Danilo Cunha
Zilmira José
Cristaldo Santos
Osmir Ferreira
Claudio Soares
O que é um select? João da Silva uma selecao
O que é um select? Frederico José buscar dados

Para os alunos que não responderam nenhuma pergunta, não aparecerá nada nas respectivas colunas (o que faz sentido, afinal se eles não responderam, não é para aparecer a pergunta nem a resposta).

Repare também que os valores nulos aparecem primeiro. Se quiser que eles sejam os últimos, pode trocar a ordenação para ORDER BY ISNULL(e.id) , a.id.


Só para constar, daria para corrigir sua query trocando o LEFT JOIN por RIGHT JOIN:

SELECT e.pergunta, a.nome, r.resposta_dada
FROM exercicio e
RIGHT JOIN resposta r ON e.id = r.exercicio_id 
RIGHT JOIN aluno a ON a.id = r.aluno_id 
WHERE e.id = 1 OR e.id IS NULL
ORDER BY e.id, a.id;

O RIGHT JOIN é similar ao LEFT JOIN, mas “ao contrário”: enquanto o LEFT traz tudo da primeira tabela, o RIGHT traz tudo da segunda (ou seja, tabela1 LEFT JOIN tabela2 é o mesmo que tabela2 RIGTH JOIN tabela1).

1 curtida

muito obrigado pela ajuda, amigo!

valeu demais, cara!
muito obrigado pelo conhecimento transmitido!

1 curtida

Uma maneira de evitar ter o OR que pode sempre trazer problemas por falta de parentesis quando conjungado com AND é colocar a condição da tabela que pode não ter dados no próprio join:

SELECT e.pergunta, a.nome, r.resposta_dada
  FROM aluno a
  LEFT JOIN resposta r ON a.id = r.aluno_id and r.exercicio_id = 1
  LEFT JOIN exercicio e ON e.id=r.exercicio_id
 ORDER BY e.id, a.id
2 curtidas

ah sim, entendi!!
muito obrigado por compartilhar isso!