Todos os produtos
Search
Central de documentação

MaxCompute:Operações JOIN no MaxCompute SQL

Última atualização: Jun 26, 2026

Posicionar uma condição de filtro na cláusula incorreta de uma consulta JOIN pode gerar resultados errados silenciosamente, especialmente em outer joins. Este tópico explica como cada tipo de JOIN trata condições de filtro em subconsultas, na cláusula ON e na cláusula WHERE externa para que suas consultas retornem exatamente o esperado.

Tipos de JOIN suportados

O MaxCompute SQL suporta as seguintes operações JOIN.

Operação

Descrição

INNER JOIN

Retorna linhas com valores correspondentes nas colunas de ambas as tabelas.

LEFT JOIN

Retorna todas as linhas da tabela à esquerda. Para linhas sem correspondência na tabela à direita, as colunas dessa tabela recebem valores NULL.

RIGHT JOIN

Retorna todas as linhas da tabela à direita. Para linhas sem correspondência na tabela à esquerda, as colunas dessa tabela recebem valores NULL.

FULL JOIN

Retorna todas as linhas de ambas as tabelas. Se uma linha não tiver correspondência na outra tabela, as colunas sem par recebem valores NULL.

LEFT SEMI JOIN

Retorna linhas da tabela à esquerda com pelo menos uma correspondência na tabela à direita. As linhas da tabela à direita não aparecem no resultado.

LEFT ANTI JOIN

Retorna linhas da tabela à esquerda sem nenhuma correspondência na tabela à direita. As linhas da tabela à direita não aparecem no resultado. Uso comum como substituto de NOT EXISTS.

Como o posicionamento do filtro afeta os resultados

Uma única instrução SQL pode combinar filtros de subconsulta, uma cláusula ON e uma cláusula WHERE externa:

SELECT *
FROM
  (SELECT * FROM A WHERE <subquery_filter_A>) A
JOIN
  (SELECT * FROM B WHERE <subquery_filter_B>) B
ON <on_condition>
WHERE <where_condition>

O MaxCompute avalia essas condições nesta ordem:

  1. <subquery_filter> — condições WHERE dentro das subconsultas

  2. <on_condition> — a cláusula ON

  3. <where_condition> — a cláusula WHERE após o JOIN

Devido a essa ordem de avaliação, o mesmo filtro lógico pode produzir resultados diferentes dependendo do local onde for posicionado.

Importante

Em outer JOINs (LEFT JOIN, RIGHT JOIN, FULL JOIN), filtrar colunas da tabela fornecedora de nulos na cláusula WHERE externa elimina as linhas com valores NULL — justamente as linhas em que a tabela preservada não encontrou correspondência. Isso converte efetivamente o outer join em um INNER JOIN. Para manter o comportamento de outer join, posicione esses filtros na cláusula ON ou em uma subconsulta.

Terminologia de outer JOIN utilizada neste tópico:

Termo

Definição

Exemplos

Tabela de linhas preservadas

Tabela cujas linhas devem obrigatoriamente aparecer no resultado

Tabela à esquerda no LEFT JOIN; tabela à direita no RIGHT JOIN; ambas as tabelas no FULL JOIN

Tabela fornecedora de nulos

Tabela que contribui com valores NULL para linhas sem correspondência

Tabela à direita no LEFT JOIN; tabela à esquerda no RIGHT JOIN; ambas as tabelas no FULL JOIN

Tabelas de teste

Os exemplos deste tópico utilizam duas tabelas, A e B.

Tabela A

CREATE TABLE A AS SELECT * FROM VALUES (1, 20180101),(2, 20180101),(2, 20180102) t (key, ds);

key

ds

1

20180101

2

20180101

2

20180102

Tabela B

CREATE TABLE B AS SELECT * FROM VALUES (1, 20180101),(3, 20180101),(2, 20180102) t (key, ds);

key

ds

1

20180101

3

20180101

2

20180102

O produto cartesiano de A e B possui 9 linhas. Ative consultas com produto cartesiano usando:

SET odps.sql.allow.cartesian=true;
SELECT * FROM A, B;

Resultado:

+------+----------+------+----------+
| key  | ds       | key2 | ds2      |
+------+----------+------+----------+
| 1    | 20180101 | 1    | 20180101 |
| 2    | 20180101 | 1    | 20180101 |
| 2    | 20180102 | 1    | 20180101 |
| 1    | 20180101 | 3    | 20180101 |
| 2    | 20180101 | 3    | 20180101 |
| 2    | 20180102 | 3    | 20180101 |
| 1    | 20180101 | 2    | 20180102 |
| 2    | 20180101 | 2    | 20180102 |
| 2    | 20180102 | 2    | 20180102 |
+------+----------+------+----------+

INNER JOIN

Um INNER JOIN retorna as linhas do produto cartesiano que satisfazem a condição de junção.

Resultado: O posicionamento da condição de filtro não altera o resultado.

Caso 1 — filtro na subconsulta:

SELECT A.*, B.*
FROM
  (SELECT * FROM A WHERE ds='20180101') A
JOIN
  (SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;

Caso 2 — filtro na cláusula ON:

SELECT A.*, B.*
FROM A JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';

Caso 3 — filtro na cláusula WHERE externa:

SELECT A.*, B.*
FROM A JOIN B
ON a.key = b.key
WHERE A.ds='20180101' AND B.ds='20180101';

Os três casos retornam:

+------+----------+------+----------+
| key  | ds       | key2 | ds2      |
+------+----------+------+----------+
| 1    | 20180101 | 1    | 20180101 |
+------+----------+------+----------+

No INNER JOIN, o mecanismo de consulta aplica primeiro a condição de junção (gerando 3 linhas correspondentes a partir do produto cartesiano de 9 linhas) e depois aplica o filtro WHERE externo. Como ambas as etapas precisam ser satisfeitas, o resultado final é idêntico independentemente do posicionamento.

LEFT JOIN

Um LEFT JOIN retorna todas as linhas da tabela à esquerda (tabela de linhas preservadas). Linhas da tabela à esquerda sem correspondência na tabela à direita aparecem com valores NULL nas colunas da tabela à direita.

Resultado: O posicionamento da condição de filtro altera o resultado.

Atenção: Filtrar uma coluna da tabela à direita (fornecedora de nulos) na cláusula WHERE externa elimina todas as linhas com NULL — aquelas em que a tabela à esquerda não teve correspondência. Isso transforma o LEFT JOIN em um INNER JOIN na prática.
  • Para filtros da tabela à esquerda: filtro em subconsulta e filtro na cláusula WHERE externa produzem o mesmo resultado.

  • Para filtros da tabela à direita: filtro em subconsulta e filtro na cláusula ON produzem o mesmo resultado.

Caso 1 — filtro na subconsulta:

SELECT A.*, B.*
FROM
  (SELECT * FROM A WHERE ds='20180101') A
LEFT JOIN
  (SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;

Resultado (2 linhas — linhas da tabela à esquerda com ds='20180101', com correspondência na tabela à direita ou NULL):

+------+----------+------+----------+
| key  | ds       | key2 | ds2      |
+------+----------+------+----------+
| 1    | 20180101 | 1    | 20180101 |
| 2    | 20180101 | NULL | NULL     |
+------+----------+------+----------+

Caso 2 — filtro na cláusula ON:

SELECT A.*, B.*
FROM A LEFT JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';

A cláusula ON filtra quais linhas de B podem corresponder, mas todas as linhas de A continuam preservadas. Do produto cartesiano de 9 linhas, apenas 1 par corresponde. As 2 linhas de A sem correspondência retornam NULL nas colunas de B.

Resultado (3 linhas — todas as linhas de A, com correspondência ou NULL):

+------+----------+------+----------+
| key  | ds       | key2 | ds2      |
+------+----------+------+----------+
| 1    | 20180101 | 1    | 20180101 |
| 2    | 20180101 | NULL | NULL     |
| 2    | 20180102 | NULL | NULL     |
+------+----------+------+----------+

Caso 3 — filtro na cláusula WHERE externa:

SELECT A.*, B.*
FROM A LEFT JOIN B
ON a.key = b.key
WHERE A.ds='20180101' AND B.ds='20180101';

A junção gera linhas com NULL em B.ds para as linhas de A sem correspondência. O filtro WHERE B.ds='20180101' não consegue corresponder a NULL, eliminando essas linhas.

Resultado (1 linha — igual ao INNER JOIN):

+------+----------+------+----------+
| key  | ds       | key2 | ds2      |
+------+----------+------+----------+
| 1    | 20180101 | 1    | 20180101 |
+------+----------+------+----------+

RIGHT JOIN

O RIGHT JOIN espelha o LEFT JOIN com as tabelas invertidas. Todas as linhas da tabela à direita (tabela de linhas preservadas) são retornadas, e as colunas da tabela à esquerda recebem NULL quando não há correspondência.

Resultado: O posicionamento da condição de filtro altera o resultado.

  • Para filtros da tabela à direita: filtro em subconsulta e filtro na cláusula WHERE externa produzem o mesmo resultado.

  • Para filtros da tabela à esquerda: filtro em subconsulta e filtro na cláusula ON produzem o mesmo resultado.

A mesma armadilha se aplica: filtrar uma coluna da tabela à esquerda (fornecedora de nulos) na cláusula WHERE externa elimina as linhas com NULL, convertendo efetivamente o RIGHT JOIN em um INNER JOIN.

FULL JOIN

Um FULL JOIN retorna todas as linhas de ambas as tabelas. Ambas atuam simultaneamente como tabelas de linhas preservadas e fornecedoras de nulos. Quando uma linha não encontra correspondência, valores NULL preenchem as colunas sem par.

Resultado: O posicionamento da condição de filtro altera o resultado.

Atenção: No FULL JOIN, filtros na cláusula ON ou na cláusula WHERE externa não restringem quais linhas são retornadas de cada tabela — eles afetam apenas se as correspondências são encontradas. Somente filtros em subconsultas restringem a entrada de forma confiável antes da junção.

Caso 1 — filtro na subconsulta:

SELECT A.*, B.*
FROM
  (SELECT * FROM A WHERE ds='20180101') A
FULL JOIN
  (SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;

Resultado (3 linhas):

+------+----------+------+----------+
| key  | ds       | key2 | ds2      |
+------+----------+------+----------+
| 2    | 20180101 | NULL | NULL     |
| 1    | 20180101 | 1    | 20180101 |
| NULL | NULL     | 3    | 20180101 |
+------+----------+------+----------+

Caso 2 — filtro na cláusula ON:

SELECT A.*, B.*
FROM A FULL JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';

Apenas 1 linha do produto cartesiano de 9 linhas atende à condição de junção. As 2 linhas de A sem correspondência recebem NULL nas colunas de B, e as 2 linhas de B sem correspondência recebem NULL nas colunas de A.

Resultado (5 linhas):

+------+----------+------+----------+
| key  | ds       | key2 | ds2      |
+------+----------+------+----------+
| NULL | NULL     | 2    | 20180102 |
| 2    | 20180101 | NULL | NULL     |
| 2    | 20180102 | NULL | NULL     |
| 1    | 20180101 | 1    | 20180101 |
| NULL | NULL     | 3    | 20180101 |
+------+----------+------+----------+

Caso 3 — filtro na cláusula WHERE externa:

SELECT A.*, B.*
FROM A FULL JOIN B
ON a.key = b.key
WHERE A.ds='20180101' AND B.ds='20180101';

A junção produz 4 linhas (3 correspondentes + 1 linha de B sem correspondência com colunas de A em NULL). O filtro WHERE elimina as linhas em que qualquer coluna seja NULL.

Resultado (1 linha):

+------+----------+------+----------+
| key  | ds       | key2 | ds2      |
+------+----------+------+----------+
| 1    | 20180101 | 1    | 20180101 |
+------+----------+------+----------+

LEFT SEMI JOIN

Um LEFT SEMI JOIN retorna linhas da tabela à esquerda que possuem pelo menos uma correspondência na tabela à direita. Como as linhas da tabela à direita não fazem parte do resultado, suas colunas não podem ser referenciadas na cláusula WHERE externa.

Resultado: O posicionamento da condição de filtro não altera o resultado.

Caso 1 — filtro na subconsulta:

SELECT A.*
FROM
  (SELECT * FROM A WHERE ds='20180101') A
LEFT SEMI JOIN
  (SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;

Caso 2 — filtro na cláusula ON:

SELECT A.*
FROM A LEFT SEMI JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';

Caso 3 — filtro na cláusula WHERE externa (filtro da tabela à direita deve estar na subconsulta):

SELECT A.*
FROM A LEFT SEMI JOIN
  (SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key
WHERE A.ds='20180101';

Os três casos retornam:

+------+----------+
| key  | ds       |
+------+----------+
| 1    | 20180101 |
+------+----------+

LEFT ANTI JOIN

Um LEFT ANTI JOIN retorna linhas da tabela à esquerda que não possuem correspondência na tabela à direita. Como as linhas da tabela à direita não fazem parte do resultado, suas colunas não podem ser referenciadas na cláusula WHERE externa.

Resultado: O posicionamento da condição de filtro altera o resultado.

  • Para filtros da tabela à esquerda: filtro em subconsulta e filtro na cláusula WHERE externa produzem o mesmo resultado.

  • Para filtros da tabela à direita: filtro em subconsulta e filtro na cláusula ON produzem o mesmo resultado.

Caso 1 — filtro na subconsulta:

SELECT A.*
FROM
  (SELECT * FROM A WHERE ds='20180101') A
LEFT ANTI JOIN
  (SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;

Resultado (1 linha):

+------+----------+
| key  | ds       |
+------+----------+
| 2    | 20180101 |
+------+----------+

Caso 2 — filtro na cláusula ON:

SELECT A.*
FROM A LEFT ANTI JOIN B
ON a.key = b.key AND A.ds='20180101' AND B.ds='20180101';

A cláusula ON restringe quais linhas de B podem servir como correspondência. Com uma condição de junção mais restritiva, mais linhas de A ficam sem par e são retornadas.

Resultado (2 linhas):

+------+----------+
| key  | ds       |
+------+----------+
| 2    | 20180101 |
| 2    | 20180102 |
+------+----------+

Caso 3 — filtro na cláusula WHERE externa (filtro da tabela à direita deve estar na subconsulta):

SELECT A.*
FROM A LEFT ANTI JOIN
  (SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key
WHERE A.ds='20180101';

A junção retorna 2 linhas e, em seguida, o filtro WHERE externo reduz para 1.

Resultado (1 linha):

+------+----------+
| key  | ds       |
+------+----------+
| 2    | 20180101 |
+------+----------+

Referência de posicionamento de filtros

Comportamento por tipo de JOIN

Tipo de JOIN

Filtro da tabela à esquerda

Filtro da tabela à direita

INNER JOIN

Qualquer posição gera o mesmo resultado

Qualquer posição gera o mesmo resultado

LEFT SEMI JOIN

Qualquer posição gera o mesmo resultado

Qualquer posição gera o mesmo resultado

LEFT JOIN

Subconsulta = WHERE externa

Subconsulta = cláusula ON

LEFT ANTI JOIN

Subconsulta = WHERE externa

Subconsulta = cláusula ON

RIGHT JOIN

Subconsulta = cláusula ON

Subconsulta = WHERE externa

FULL JOIN

Apenas subconsulta

Apenas subconsulta

Recomendações

Utilize filtros em subconsultas para outer JOINs. Filtros em subconsultas restringem os dados de entrada antes da execução da junção, preservando intacta a semântica do join. Essa é a abordagem mais segura para todos os tipos de JOIN.

Se você usar a cláusula ON para filtros da tabela fornecedora de nulos em um LEFT JOIN ou RIGHT JOIN, a semântica de outer join será mantida. Colocar esses filtros na cláusula WHERE externa elimina as linhas com NULL e converte efetivamente o outer join em um INNER JOIN.

No FULL JOIN, filtros em subconsultas são a única opção que restringe a entrada de forma confiável — filtros na cláusula ON ou na cláusula WHERE externa alteram quais linhas correspondem, mas não excluem linhas sem correspondência de nenhuma das tabelas.

Próximos passos

  • JOIN — referência de sintaxe para operações JOIN padrão no MaxCompute SQL

  • SEMI JOIN — referência de sintaxe para LEFT SEMI JOIN e LEFT ANTI JOIN

  • MAPJOIN HINT — melhore o desempenho ao juntar uma tabela grande com uma tabela pequena

  • DISTRIBUTED MAPJOIN — melhore o desempenho ao juntar uma tabela grande com uma tabela de tamanho médio

  • SKEWJOIN HINT — lide com valores de chave quente que causam problemas de longa duração em operações JOIN