Categorias:

Sintaxe de consulta

Trabalho com junções

Uma junção combina linhas de duas tabelas para criar uma nova linha combinada que pode ser usada na consulta.

Introdução

As junções são úteis quando os dados nas tabelas estão relacionados. Por exemplo, uma tabela pode conter informações sobre projetos e outra pode conter informações sobre os funcionários que trabalham nesses projetos.

CREATE TABLE projects (
  project_id INT,
  project_name VARCHAR);

INSERT INTO projects VALUES
  (1000, 'COVID-19 Vaccine'),
  (1001, 'Malaria Vaccine'),
  (1002, 'NewProject');

CREATE TABLE employees (
  employee_id INT,
  employee_name VARCHAR,
  project_id INT);

INSERT INTO employees VALUES
  (10000001, 'Terry Smith', 1000),
  (10000002, 'Maria Inverness', 1000),
  (10000003, 'Pat Wang', 1001),
  (10000004, 'NewEmployee', NULL);
Copy

Consulte as tabelas para visualizar os dados:

SELECT * FROM projects ORDER BY project_ID;
Copy
+------------+------------------+
| PROJECT_ID | PROJECT_NAME     |
|------------+------------------|
|       1000 | COVID-19 Vaccine |
|       1001 | Malaria Vaccine  |
|       1002 | NewProject       |
+------------+------------------+
SELECT * FROM employees ORDER BY employee_ID;
Copy
+-------------+-----------------+------------+
| EMPLOYEE_ID | EMPLOYEE_NAME   | PROJECT_ID |
|-------------+-----------------+------------|
|    10000001 | Terry Smith     |       1000 |
|    10000002 | Maria Inverness |       1000 |
|    10000003 | Pat Wang        |       1001 |
|    10000004 | NewEmployee     |       NULL |
+-------------+-----------------+------------+

As duas tabelas unidas geralmente contêm uma ou mais colunas em comum para que as linhas de uma tabela possam ser associadas com as linhas correspondentes na outra tabela. Por exemplo, nestas tabelas de amostra, cada linha na tabela de projetos tem um número de ID de projeto exclusivo, e cada linha na tabela de funcionários inclui o número de ID do projeto ao qual o funcionário está atualmente atribuído.

A operação de junção especifica, explícita ou implicitamente, como relacionar linhas em uma tabela às linhas correspondentes na outra tabela, normalmente referenciando uma ou mais colunas comuns, como project_id. Por exemplo, o seguinte une as tabelas projects e employees que foram criadas anteriormente:

SELECT p.project_ID, project_name, employee_ID, employee_name, e.project_ID
  FROM projects AS p JOIN employees AS e
    ON e.project_ID = p.project_ID
  ORDER BY p.project_ID, e.employee_ID;
Copy
+------------+------------------+-------------+-----------------+------------+
| PROJECT_ID | PROJECT_NAME     | EMPLOYEE_ID | EMPLOYEE_NAME   | PROJECT_ID |
|------------+------------------+-------------+-----------------+------------|
|       1000 | COVID-19 Vaccine |    10000001 | Terry Smith     |       1000 |
|       1000 | COVID-19 Vaccine |    10000002 | Maria Inverness |       1000 |
|       1001 | Malaria Vaccine  |    10000003 | Pat Wang        |       1001 |
+------------+------------------+-------------+-----------------+------------+

Embora uma única operação de junção possa unir apenas duas tabelas, as junções podem ser encadeadas juntas. O resultado de uma junção é um objeto tipo tabela, e esse objeto tipo tabela pode então ser unido a outro objeto tipo tabela. Conceitualmente, a ideia é semelhante ao seguinte; esta não é a sintaxe real:

table1 JOIN (table2 JOIN table3)
Copy

Neste pseudocódigo, table2 e table3 são unidos primeiro. A tabela resultante dessa junção é então unida com table1.

As junções podem ser aplicadas não apenas a tabelas, mas também a outros objetos semelhantes a tabelas. Você pode unir:

  • Uma tabela.

  • Uma exibição (materializada ou não).

  • Um literal de tabela.

  • Uma expressão que é avaliada ao equivalente de uma tabela (contendo uma ou mais colunas e zero ou mais linhas). Por exemplo:

    • O conjunto de resultados retornado por uma função de tabela.

    • O conjunto de resultados definido devolvido por uma subconsulta que retorna uma tabela.

Quando este tópico se referir a unir uma tabela, geralmente significa unir qualquer objeto semelhante a uma tabela.

Nota

O Snowflake pode melhorar o desempenho eliminando junções desnecessárias. Para obter mais informações, consulte Compreensão de como o Snowflake consegue eliminar junções redundantes.

Tipos de junções

O Snowflake suporta os seguintes tipos de junções:

Nota

O Snowflake também suporta ASOF JOIN para analisar dados de séries temporais. Para obter mais informações, consulte ASOF JOIN e Análise de dados de séries temporais.

Junção interna

Uma junção interna emparelha cada linha de uma tabela com as linhas correspondentes da outra tabela.

O exemplo a seguir mostra uma junção interna:

SELECT p.project_ID, project_name, employee_ID, employee_name, e.project_ID
  FROM projects AS p INNER JOIN employees AS e
    ON e.project_id = p.project_id
  ORDER BY p.project_ID, e.employee_ID;
Copy
+------------+------------------+-------------+-----------------+------------+
| PROJECT_ID | PROJECT_NAME     | EMPLOYEE_ID | EMPLOYEE_NAME   | PROJECT_ID |
|------------+------------------+-------------+-----------------+------------|
|       1000 | COVID-19 Vaccine |    10000001 | Terry Smith     |       1000 |
|       1000 | COVID-19 Vaccine |    10000002 | Maria Inverness |       1000 |
|       1001 | Malaria Vaccine  |    10000003 | Pat Wang        |       1001 |
+------------+------------------+-------------+-----------------+------------+

Neste exemplo, a saída contém duas colunas denominadas PROJECT_ID. Uma coluna PROJECT_ID é da tabela projects e a outra é da tabela employees. Para cada linha na saída, os valores nas duas colunas PROJECT_ID correspondem porque a consulta especificou e.project_id = p.project_id.

A saída inclui apenas pares válidos; ou seja, linhas que correspondem à condição de junção. Neste exemplo, não há nenhuma linha para o projeto denominado NewProject, que ainda não tem funcionários atribuídos, ou para o funcionário denominado NewEmployee, que ainda não foi atribuído a nenhum projeto.

Junção externa

Uma junção externa lista todas as linhas da tabela especificada, mesmo que essas linhas não tenham correspondência na outra tabela. Por exemplo, uma junção externa à esquerda entre projetos e funcionários lista todos os projetos, incluindo os que ainda não têm nenhum funcionário atribuído.

SELECT p.project_name, e.employee_name
  FROM projects AS p LEFT OUTER JOIN employees AS e
    ON e.project_ID = p.project_ID
  ORDER BY p.project_name, e.employee_name;
Copy
+------------------+-----------------+
| PROJECT_NAME     | EMPLOYEE_NAME   |
|------------------+-----------------|
| COVID-19 Vaccine | Maria Inverness |
| COVID-19 Vaccine | Terry Smith     |
| Malaria Vaccine  | Pat Wang        |
| NewProject       | NULL            |
+------------------+-----------------+

O projeto denominado NewProject é incluído nesta saída, mesmo que não haja nenhuma linha correspondente na tabela employees. Como não há nomes de funcionários correspondentes para o projeto denominado NewProject, o nome do funcionário é NULL.

Uma junção externa direita lista todos os funcionários (independentemente do projeto).

SELECT p.project_name, e.employee_name
  FROM projects AS p RIGHT OUTER JOIN employees AS e
    ON e.project_ID = p.project_ID
  ORDER BY p.project_name, e.employee_name;
Copy
+------------------+-----------------+
| PROJECT_NAME     | EMPLOYEE_NAME   |
|------------------+-----------------|
| COVID-19 Vaccine | Maria Inverness |
| COVID-19 Vaccine | Terry Smith     |
| Malaria Vaccine  | Pat Wang        |
| NULL             | NewEmployee     |
+------------------+-----------------+

Uma junção externa completa lista todos os projetos e todos os funcionários.

SELECT p.project_name, e.employee_name
  FROM projects AS p FULL OUTER JOIN employees AS e
    ON e.project_ID = p.project_ID
  ORDER BY p.project_name, e.employee_name;
Copy
+------------------+-----------------+
| PROJECT_NAME     | EMPLOYEE_NAME   |
|------------------+-----------------|
| COVID-19 Vaccine | Maria Inverness |
| COVID-19 Vaccine | Terry Smith     |
| Malaria Vaccine  | Pat Wang        |
| NewProject       | NULL            |
| NULL             | NewEmployee     |
+------------------+-----------------+

Junção cruzada

Uma junção cruzada combina cada linha da primeira tabela com cada linha da segunda, criando todas as combinações possíveis de linhas, o que é chamado de produto cartesiano. Como a maioria das linhas de resultados contém partes de linhas que não estão realmente relacionadas, uma junção cruzada raramente é útil por si só. Na verdade, as junções cruzadas são geralmente o resultado de se omitir acidentalmente a condição de junção.

O resultado de uma junção cruzada pode ser muito grande e caro. Se a primeira tabela tiver N linhas e a segunda tabela tiver M linhas, então o resultado são N x M linhas. Por exemplo, se a primeira tabela tiver 100 linhas e a segunda tabela tiver 1000 linhas, então o conjunto de resultados contém 100.000 linhas.

A consulta a seguir mostra uma junção cruzada:

Nota

Esta consulta não contém cláusula ON nem filtro.

SELECT p.project_name, e.employee_name
  FROM projects AS p CROSS JOIN employees AS e
  ORDER BY p.project_ID, e.employee_ID;
Copy
+------------------+-----------------+
| PROJECT_NAME     | EMPLOYEE_NAME   |
|------------------+-----------------|
| COVID-19 Vaccine | Terry Smith     |
| COVID-19 Vaccine | Maria Inverness |
| COVID-19 Vaccine | Pat Wang        |
| COVID-19 Vaccine | NewEmployee     |
| Malaria Vaccine  | Terry Smith     |
| Malaria Vaccine  | Maria Inverness |
| Malaria Vaccine  | Pat Wang        |
| Malaria Vaccine  | NewEmployee     |
| NewProject       | Terry Smith     |
| NewProject       | Maria Inverness |
| NewProject       | Pat Wang        |
| NewProject       | NewEmployee     |
+------------------+-----------------+

Você pode tornar a saída de uma junção cruzada mais útil aplicando um filtro na cláusula WHERE:

SELECT p.project_name, e.employee_name
  FROM projects AS p CROSS JOIN employees AS e
  WHERE e.project_ID = p.project_ID
  ORDER BY p.project_ID, e.employee_ID;
Copy
+------------------+-----------------+
| PROJECT_NAME     | EMPLOYEE_NAME   |
|------------------+-----------------|
| COVID-19 Vaccine | Terry Smith     |
| COVID-19 Vaccine | Maria Inverness |
| Malaria Vaccine  | Pat Wang        |
+------------------+-----------------+

O resultado desta junção cruzada e filtro é o mesmo que o resultado da seguinte junção interna:

SELECT p.project_name, e.employee_name
  FROM projects AS p INNER JOIN employees AS e
    ON e.project_ID = p.project_ID
  ORDER BY p.project_ID, e.employee_ID;
Copy
+------------------+-----------------+
| PROJECT_NAME     | EMPLOYEE_NAME   |
|------------------+-----------------|
| COVID-19 Vaccine | Terry Smith     |
| COVID-19 Vaccine | Maria Inverness |
| Malaria Vaccine  | Pat Wang        |
+------------------+-----------------+

Importante

Embora as duas consultas neste exemplo produzam a mesma saída quando usam a mesma condição (e.project_id = p.project_id) em cláusulas diferentes (WHERE e FROM ... ON ...), é possível construir pares de consultas que usam a mesma condição, mas que não produzem a mesma saída.

Os exemplos mais comuns envolvem junções externas. Se você executar table1 LEFT OUTER JOIN table2, para as linhas em table1 que não têm correspondência, as colunas que teriam vindo de table2 conterão NULL. Um filtro como WHERE table2.ID = table1.ID filtra linhas nas quais table2.id ou table1.id contém um NULL, enquanto uma junção externa explícita na cláusula FROM ... ON ... não filtra linhas com valores NULL. Em outras palavras, uma junção externa com um filtro pode não atuar como uma junção externa.

Junção natural

Uma junção natural une duas tabelas em colunas que têm os mesmos nomes e tipos de dados compatíveis. Tanto a tabela employees quanto a projects criadas anteriormente têm uma coluna denominada project_ID. Uma junção natural constrói implicitamente a cláusula ON: ON projects.project_ID = employees.project_ID.

Se duas tabelas tiverem várias colunas em comum, uma junção natural usará todas as colunas comuns na cláusula ON construída. Por exemplo, se duas tabelas tiverem colunas denominadas city e province, uma junção natural construirá a seguinte cláusula ON:

ON table2.city = table1.city AND table2.province = table1.province
Copy

A saída de uma junção natural inclui apenas uma cópia de cada uma das colunas compartilhadas. Por exemplo, a consulta a seguir produz uma junção natural que contém todas as colunas nas duas tabelas, exceto que omite todas as cópias, exceto uma, das colunas redundantes project_id:

SELECT *
  FROM projects NATURAL JOIN employees
  ORDER BY employee_id;
Copy
+------------+------------------+-------------+-----------------+
| PROJECT_ID | PROJECT_NAME     | EMPLOYEE_ID | EMPLOYEE_NAME   |
|------------+------------------+-------------+-----------------|
|       1000 | COVID-19 Vaccine |    10000001 | Terry Smith     |
|       1000 | COVID-19 Vaccine |    10000002 | Maria Inverness |
|       1001 | Malaria Vaccine  |    10000003 | Pat Wang        |
+------------+------------------+-------------+-----------------+

Você pode combinar uma junção natural com uma junção externa.

Você não pode combinar uma cláusula ON de junção natural porque a condição de junção já está implícita. Entretanto, você pode usar uma cláusula WHERE para filtrar os resultados de uma junção natural.

Implementação de junções

Sintaticamente, há duas formas de unir tabelas:

  • Use a subcláusula JOIN na subcláusula ON da cláusula FROM.

  • Use a cláusula WHERE com a cláusula FROM.

A Snowflake recomenda usar a subcláusula ON na cláusula FROM porque a sintaxe é mais flexível. Além disso, especificar o predicado na subcláusula ON evita o problema de filtrar acidentalmente linhas com valores NULL ao usar uma cláusula WHERE para especificar a condição de junção para uma junção externa.

Além disso, você pode usar a palavra-chave DIRECTED para impor a ordem de junção das tabelas. Quando você especifica essa palavra-chave, a primeira tabela, ou a da esquerda, é verificada antes da segunda tabela, ou a da direita. Por exemplo, o1 INNER DIRECTED JOIN o2 verifica a tabela o1 antes da tabela o2. Se a palavra-chave DIRECTED for adicionada, o tipo de junção (por exemplo, INNER ou OUTER) é necessário. Para obter mais informações, consulte JOIN.

Nota

A junção direcionada é um recurso em versão preliminar disponível para todas as contas.