Agora chegou a hora de falar da vida real. Daquele lado que ninguém escapa: erros. Pegar, corrigir e entender erros é parte obrigatória de quem mexe com dados. Bora ver quais são as armadilhas mais comuns quando você usa JOIN no SQL e como fugir delas.
Erro 1: Esquecer a condição de junção — criando produto cartesiano
O erro mais comum é esquecer de colocar a condição de junção usando ON. Nesse caso, rola um produto cartesiano, onde cada linha da primeira tabela se junta com cada linha da segunda. O resultado? Um monte de linha sem sentido nenhum, só pra te confundir.
Vamos ver um exemplo. Suponha que temos as seguintes tabelas:
Estudantes (students):
| student_id | name |
|---|---|
| 1 | Otto |
| 2 | Anna |
Cursos (courses):
| course_id | course_name |
|---|---|
| 101 | Matemática |
| 102 | História |
Agora vamos escrever uma query esquecendo do ON:
SELECT *
FROM students
JOIN courses;
Resultado:
| student_id | name | course_id | course_name |
|---|---|---|---|
| 1 | Otto | 101 | Matemática |
| 1 | Otto | 102 | História |
| 2 | Anna | 101 | Matemática |
| 2 | Anna | 102 | História |
Parece certo isso? Nem um pouco! Esse pesadelo aí é o tal do produto cartesiano.
Como resolver: usa o ON pra dizer como os dados das tabelas estão ligados.
SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;
E aí já aparece outro tipo de erro...
Proteção contra vacilo
Isso é tão comum que no PostgreSQL é proibido usar JOIN sem ON e sem condição.
Se você realmente quiser juntar cada linha com cada linha, pode usar a sintaxe sem JOIN:
SELECT *
FROM students, courses;
Mais um caso — quando JOIN sem ON funciona:
- Com
NATURAL JOIN— ele junta automaticamente pelas colunas que têm o mesmo nome. - Com
USING— você diz quais colunas usar pra juntar. CROSS JOIN— sempre sem condição, é o produto cartesiano mesmo.
Erro 2: Condição de junção errada
Às vezes você coloca a condição de junção, mas faz isso errado. Por exemplo, junta tabelas por campos que não têm nada a ver.
Suponha que a gente quer listar estudantes e os cursos em que estão inscritos, mas erra e junta as tabelas por campos que não têm relação:
SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;
Essa query vai dar resultado errado, porque student_id e course_id não têm nada a ver um com o outro.
Como resolver: confere se você está usando as colunas certas pra juntar. O jeito certo seria assim (se você tiver uma tabela enrollments ligando estudantes e cursos):
SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;
Erro 3: Duplicação de linhas no resultado
Quando você coloca vários JOIN na query, às vezes isso gera linhas duplicadas. Isso acontece se nas tabelas do JOIN tem registros repetidos, ou se você colocou a condição de junção errada.
Por exemplo, o estudante Otto está inscrito duas vezes no mesmo curso na tabela enrollments.
Registros em enrollments:
| student_id | course_id |
|---|---|
| 1 | 101 |
| 1 | 101 |
Agora a query com JOIN vai dar esse resultado:
SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;
Resultado:
| name | course_name |
|---|---|
| Otto | Matemática |
| Otto | Matemática |
Como resolver: primeiro, confere se não tem dados duplicados nas suas tabelas. Segundo, se isso for esperado, remove os duplicados usando DISTINCT:
SELECT DISTINCT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;
Erro 4: Perda de linhas usando INNER JOIN
INNER JOIN só retorna as linhas que têm correspondência nas duas tabelas. Se faltar valor em uma delas, a linha é descartada. Você pode perder dados se escolher o tipo de junção errado.
Por exemplo, temos um estudante que ainda não se inscreveu em nenhum curso:
Estudantes (students):
| student_id | name |
|---|---|
| 1 | Otto |
| 2 | Anna |
| 3 | Dhany |
Inscrições (enrollments):
| student_id | course_id |
|---|---|
| 1 | 101 |
| 2 | 102 |
Agora a query com INNER JOIN:
SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;
Resultado:
| name | course_name |
|---|---|
| Otto | Matemática |
| Anna | História |
Cadê o Dhany? Se você quiser incluir estudantes sem cursos, tem que usar LEFT JOIN:
SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id;
Erro 5: Tratamento errado de valores NULL
Se em uma das tabelas tem linhas com valores vazios (NULL), elas podem ficar de fora do resultado (por exemplo, quando você usa condições de filtro).
Exemplo: você usa LEFT JOIN, mas depois coloca um WHERE pra filtrar.
SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id
WHERE courses.course_name = 'Matemática';
Agora os estudantes sem curso não vão aparecer no resultado, mesmo usando LEFT JOIN.
Como resolver: se quiser incluir linhas sem curso, troca o WHERE por ON ou adiciona uma condição extra:
SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id
WHERE courses.course_name IS NULL OR courses.course_name = 'Matemática';
Erro 6: Confusão entre tipos de junção
Você se confunde sobre qual tipo de junção usar. Por exemplo, usa RIGHT JOIN quando dava pra usar LEFT JOIN só trocando a ordem das tabelas.
Como não se enrolar:
- Prefira
LEFT JOINsempre que puder. É mais intuitivo. - Mude a ordem das tabelas pra evitar precisar de
RIGHT JOIN.
GO TO FULL VERSION