CodeGym /Cursos /SQL SELF /Condições extras no JOIN: ON ... AND...

Condições extras no JOIN: ON ... AND ...

SQL SELF
Nível 12 , Lição 2
Disponível
JOIN: ON ... AND ...

Você já sabe como juntar tabelas usando JOIN. Mas na vida real, só bater as chaves pode não ser suficiente. Muitas vezes rola a necessidade de juntar dados só se eles baterem em algum critério extra — tipo, só registros ativos, só dados do ano atual ou só pedidos finalizados.

É aí que entra a extensão do ON usando AND.

Condições extras no JOIN ... ON te deixam controlar exatamente quais linhas vão entrar na junção, antes mesmo do SQL começar a montar o resultado. Isso faz sua query ficar:

  • Mais rápida (menos linhas passam pelo JOIN),
  • Mais precisa (o filtro já rola na hora da junção),
  • Mais previsível quando você usa LEFT JOIN (diferente do filtro no WHERE).

Exemplo: Só registros ativos em cursos

Imagina que a tabela enrollments tem o status da participação do estudante: active, dropped, pending.

Tabela students:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

Atualizando a tabela enrollments:

student_id course_id status
1 101 active
1 103 active
2 102 dropped
3 101 active

Tabela courses:

id name
101 Mathematics
102 Physics
103 Computer Science

Agora a gente quer pegar só os estudantes que têm cursos ativos:

SELECT 
    students.name AS student_name,
    courses.name AS course_name
FROM students 
INNER JOIN enrollments 
    ON students.id = enrollments.student_id
    AND enrollments.status = 'active'
INNER JOIN courses 
    ON enrollments.course_id = courses.id;

Resultado:

student_name course_name
Otto Song Mathematics
Otto Song Computer Science
Alex Lin Mathematics

Aqui a gente colocou AND enrollments.status = 'active' dentro do ON, pra junção rolar só com os registros ativos, e não filtrar depois de juntar tudo.

Por que não WHERE?

Dava pra escrever assim também:

...
WHERE enrollments.status = 'active'

Mas isso tem outro comportamento com LEFT JOIN. O filtro no WHERE remove linhas que não têm correspondência (NULL), e aí o LEFT JOIN vira um INNER JOIN.

Já a condição AND enrollments.status = 'active' dentro do ON já limita as linhas que vão ser juntadas — controla o que entra na junção, não só filtra depois.

Esse jeito é importante principalmente quando você quer manter linhas de uma tabela mesmo se não tiver valor correspondente na outra (bem comum em relatórios e análises).

Mais exemplos de ON ... AND ...

Tabela students:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

Tabela enrollments:

student_id course_id status enrolled_at
1 101 active 2025-02-01
1 103 active 2025-03-05
2 102 dropped 2024-05-15
3 101 active 2025-03-12

Tabela courses:

id name
101 Math
102 Physics
103 CS

Exemplo: só cursos do ano atual

SELECT
    students.name,
    courses.name,
    enrollments.enrolled_at
FROM students
JOIN enrollments
    ON students.id = enrollments.student_id
    AND EXTRACT(YEAR FROM enrollments.enrolled_at) = EXTRACT(YEAR FROM CURRENT_DATE)
JOIN courses
    ON enrollments.course_id = courses.id;

Aqui a gente só junta os registros que são do ano atual.

name name enrolled_at
Otto Song Math 2025-02-01
Otto Song CS 2025-03-05
Alex Lin Math 2025-03-12

Exemplo: excluindo por valor

JOIN enrollments
    ON students.id = enrollments.student_id
    AND enrollments.status != 'dropped'

Aqui a gente exclui estudantes que saíram do curso na hora da junção, não depois.

name name
Otto Song Math
Otto Song CS
Alex Lin Math

Quando a condição tá dentro do ON, o PostgreSQL pode otimizar o plano de junção e processar menos linhas. Isso faz muita diferença quando tem muito dado. Filtrar dentro é mais eficiente do que "cortar" depois do JOIN.

JOIN ON — não é só chave, não!

Muita gente acha que ON é só id = id. Mas na real, dá pra colocar:

  • Operadores lógicos: AND, OR, NOT
  • Comparações: >, <, <>, BETWEEN, IN
  • Expressões: EXTRACT, DATE_TRUNC, COALESCE, NULLIF

Juntando tudo

Tabela students:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

Tabela faculties:

id name
10 Engineering
20 Natural Sciences
30 ← sem nome (NULL)

Tabela courses:

id name teacher faculty_id
101 Math Liam Park 10
102 Physics Chloe Zhang 20
103 CS Noah Kim 10
104 PE Ava Chen 30

Tabela enrollments:

student_id course_id status
1 101 active
1 103 active
2 102 dropped
3 101 active
3 104 active
SELECT
    s.name AS student_name,
    c.name AS course_name,
    f.name AS faculty_name
FROM students s
JOIN enrollments e
    ON s.id = e.student_id
    AND e.status = 'active'
JOIN courses c
    ON e.course_id = c.id
    AND c.name != 'PE'
JOIN faculties f
    ON c.faculty_id = f.id
    AND f.name IS NOT NULL;

Aqui a gente filtra ao mesmo tempo por:

  • Registros ativos,
  • Cursos, menos "PE",
  • Faculdades que têm nome.

Resultado da query:

student_name course_name faculty_name
Otto Song Math Engineering
Otto Song CS Engineering
Alex Lin Math Engineering

Espero que você tenha curtido essa aula. Você vai usar vários JOINs com filtros nas suas queries o tempo todo. Quase sempre :)

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION