Cláusulas INNER JOIN, LEFT JOIN e RIGHT JOIN

Associações de tabelas podem ser utilizadas para diversas finalidades, como converter em informação os dados encontrados em duas ou mais tabelas. Esse tipo de operação pode ser feito por meio das cláusulas WHERE e JOIN. Além disso, as tabelas podem ser combinadas por meio de uma condição ou um grupo de condições de junção. Por exemplo, podemos usar as chaves estrangeiras como condição para relacionar as tabelas.


Guia do artigo:

É importante salientar que as tabelas devem ser associadas em pares, embora seja possível usar um único comando para juntar várias tabelas. Uma das formas mais usadas é a associação da chave primária da primeira tabela com a chave estrangeira da segunda.

Diferentes tipos de associação podem ser escritos com a ajuda das cláusulas JOIN e WHERE. Outro exemplo: podemos obter apenas os dados relacionados entre duas tabelas associadas. Também podemos combinar duas tabelas de forma que seus dados relacionados e os não-relacionados sejam obtidos.

As tabelas podem, ainda, ser associadas de modo que sejam gerados não apenas dados relacionados entre elas, mas também dados não relacionados da tabela encontrada à esquerda ou à direita da cláusula JOIN.

Também podemos associar as tabelas por meio das cláusulas JOIN e WHERE para a obtenção do produto cartesiano, que nada mais é do que um conjunto de resultados com todas as linhas que são geradas a partir desta associação.

JOIN

A cláusula JOIN permite que os dados de várias tabelas sejam combinados com base na relação existente entre elas. Por meio dessa cláusula, os dados de uma tabela são usados para selecionar os dados pertencentes à outra tabela.

Com a cláusula JOIN, podemos especificar quais colunas das tabelas serão associadas. Para isso, será preciso definir uma chave estrangeira de uma tabela e a chave relacionada em outra tabela.

Os valores pertencentes às colunas das tabelas associadas podem ser comparados entre si por meio de um operador lógico definido pela cláusula JOIN e usada pelo operador ON, como o sinal de igual (=).

Veja o exemplo simplificado de uma sintaxe de cláusula de associação:

FROM nome_da_primeira_tabela tipo_de_associação nome_da_segunda_tabela [ON (condição_de_associação) ]

Onde:

  • tipo_de_associação: Permite identificar uma das seguintes associações: OUTER JOIN, INNER JOIN e CROSS JOIN (que serão descritas em detalhes mais adiante);
  • condição_de_associação: Define um critério para avaliar duas linhas de dados que já estão associadas.

A forma mais indicada para a especificação de associações é a cláusula FROM, que permite que as condições JOIN sejam identificadas em relação às condições de busca referenciadas na cláusula WHERE.

Vejamos um exemplo simples da associação de tabelas (estou usando as tabelas criadas no artigo anterior):


SELECT *
FROM CLIENTES AS C 
JOIN PEDIDOS AS P ON C.IDCLIENTE = P.IDPEDIDO

Podemos fazer também o mesmo especificando quais tabelas serão retornadas:


SELECT C.NOME, C.STATUS, P.DESCRICAO, P.VALOR 
FROM CLIENTES AS C 
JOIN PEDIDOS AS P ON C.IDCLIENTE = P.IDPEDIDO

Repare que posso consultar colunas de outras tabelas no mesmo SELECT, desde que, é claro, eu referencie esta tabela no meu JOIN.

É normal encontrarmos colunas com o mesmo nome, vindos de tabelas diferentes. Para que não haja confusão e consigamos a identificação correta da procedência dos dados, devemos qualificar o nome de uma coluna com o nome da tabela da qual ela é originada.

É recomendado que se use esta qualificação principalmente quando usamos o SELECT, já que este comando não permite identificar a origem de cada coluna. Os aliases (apelidos) da tabela também auxiliam nessa identificação.

Veja um exemplo usando a cláusula WHERE para especificar uma condição de associação, já com as recomendações acima:


SELECT CLIENTES.IDCLIENTE, CLIENTES.NOME, PEDIDOS.DESCRICAO, PEDIDOS.VALOR
FROM CLIENTES, PEDIDOS
WHERE CLIENTES.IDCLIENTE = PEDIDOS.IDPEDIDO AND PEDIDOS.VALOR > 50.00

O processamento de uma associação atende a uma sequencia lógica, sendo que, em primeiro lugar, são executadas as condições de associação da cláusula FROM. Depois, são aplicadas as condições de busca e de associação encontradas na cláusula WHERE. Por último, são executadas as condições de busca na cláusula HAVING (considerando, é claro, que tenhamos estas condições de associação em nossa consulta).

Os tipos de dados das colunas vindas de tabelas associadas não precisam ser necessariamente idênticos, mas devem ser compatíveis, para que o SQL Server consiga fazer a conversão. A condição de associação pode (se preciso) usar a função CAST para converter tipos de dados que não podem ser transformados facilmente.

INNER JOIN

A cláusula INNER JOIN permite usar um operador de comparação para comparar os valores de colunas provenientes de tabelas associadas. Por meio desta cláusula, os registros de duas tabelas são usados para que sejam gerados os dados relacionados de ambas. Usamos as cláusulas WHERE e FROM para especificar esse tipo de associação.

Saiba mais: INNER JOIN

No exemplo abaixo, iremos criar as tabelas Cargo e Funcionario, cujas colunas são as seguintes:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

Repare que temos a coluna IdCargo nas duas tabelas, porém, ela possui finalidades distintas: enquanto na tabela Cargo, ela é chave primária, na tabela Funcionario ela é chave estrangeira.

Assim, a associação entre as tabelas é feita pela coluna IdCargo e podemos identificar os cargos existentes e o nome dos funcionários que desempenham cada um deles.

Usamos então a cláusula INNER JOIN para obtermos os dados relacionados das duas tabelas, para que sejam retornados todos os cargos ocupados pelos funcionários, bem como todos os funcionários que desempenham algum cargo. Veja como isso é feito no script abaixo:


SELECT C.NOMECARGO [CARGO], F.NOMEFUNCIONARIO AS [FUNCIONÁRIO], F.SALARIOFUNCIONARIO AS [SALÁRIO]
FROM CARGO AS C
INNER JOIN FUNCIONARIO AS F ON C.IDCARGO = F.IDCARGO

Nossa consulta terá o seguinte retorno:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

Podemos usar também a cláusula WHERE e termos o mesmo resultado. O script ficará assim:

SELECT C.NOMECARGO [CARGO], F.NOMEFUNCIONARIO AS [FUNCIONÁRIO], F.SALARIOFUNCIONARIO AS [SALÁRIO]
FROM CARGO AS C, FUNCIONARIO AS F
WHERE C.IDCARGO = F.IDCARGO

Independente da cláusula usada, o relacionamento entre as tabelas será feito, como dito anteriormente, por meio da chave primária da tabela Cargo e da chave estrangeira da tabela Funcionario.

Note que, no retorno de nossas consultas, o único cargo que não é exibido pra nós é o Programador Sr. já que não há nenhum funcionário relacionado a este cargo. Para que exibamos também este cargo usamos a cláusula que será explicada a seguir.

LEFT JOIN

A cláusula LEFT JOIN ou LEFT OUTER JOIN permite obter não apenas os dados relacionados de duas tabelas, mas também os dados não relacionados encontrados na tabela à esquerda da cláusula JOIN. Caso não existam dados relacionados entre as tabelas à esquerda e a direita do JOIN, os valores resultantes de todas as colunas da lista de seleção da tabela à direita serão nulos.

Saiba mais: LEFT JOIN

Para exemplificar melhor, vejamos os exemplos das tabelas Cargo e Funcionário. Como dito anteriormente, o único cargo que não contém funcionário vinculado a ele é o Programador Sr. Para obtermos mesmo assim esse cargo, usamos a cláusula LEFT JOIN à esquerda do sinal de igual (=), como no script abaixo:


SELECT C.NOMECARGO [CARGO], F.NOMEFUNCIONARIO AS [FUNCIONÁRIO], F.SALARIOFUNCIONARIO AS [SALÁRIO]
FROM CARGO AS C
LEFT JOIN FUNCIONARIO AS F ON C.IDCARGO = F.IDCARGO

Seu resultado será o seguinte:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

RIGHT JOIN

Ao contrário do LEFT JOIN, a cláusula RIGHT JOIN ou RIGHT OUTER JOIN retorna todos os dados encontrados na tabela à direita de JOIN. Caso não existam dados associados entre as tabelas à esquerda e à direita de JOIN, serão retornados valores nulos.

Suponhamos que a posição das tabelas usadas nos exemplos anteriores foi trocada. Se mesmo assim desejamos obter o mesmo resultado obtido anteriormente, podemos usar a cláusula RIGHT JOIN, assim iremos conseguir tanto os dados relacionados como os não relacionados disponíveis na tabela à direita da cláusula JOIN.

Assim, devemos usar o script abaixo:

SELECT C.NOMECARGO [CARGO], F.NOMEFUNCIONARIO AS [FUNCIONÁRIO], F.SALARIOFUNCIONARIO AS [SALÁRIO]
FROM FUNCIONARIO AS F
RIGHT JOIN CARGO AS C ON F.IDCARGO = C.IDCARGO

Que terá o seguinte retorno:

+----------------+--------------+--------+
| cargo          | func         | salario|
+----------------+--------------+--------+
| Web Designer PI| tiririca     | 2500   |
| Programador Jr | ze da pizza  | 2250   |
| programador PI | Tiozao do gas| 2750   |
| DBA Jr         | Adalberto    | 2300   |
| Programador Jr | Marisa       | 2500   |
+----------------+--------------+--------+ 

Perceba que somente inverti a ordem das tabelas nas cláusulas FROM e RIGHT JOIN em relação ao exemplo com LEFT JOIN.

FULL JOIN

Todas as linhas de dados da tabela à esquerda de JOIN e da tabela à direita serão retornadas pela cláusula FULL JOIN ou FULL OUTER JOIN. Caso uma linha de dados não esteja associada a qualquer linha da outra tabela, os valores das colunas a lista de seleção serão nulos. Caso contrário, os valores obtidos serão baseados nas tabelas usadas como referência.

A cláusula FULL JOIN deve ser usada como no exemplo a seguir:


SELECT C.NOMECARGO [CARGO], F.NOMEFUNCIONARIO AS [FUNCIONÁRIO], F.SALARIOFUNCIONARIO AS [SALÁRIO]
FROM FUNCIONARIO AS F
FULL JOIN CARGO AS C ON F.IDCARGO = C.IDCARGO

No caso do nosso exemplo, o resultado será igual aos anteriores:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

CROSS JOIN

Todos os dados da tabela à esquerda de JOIN são cruzados com os dados da tabela à direita de JOIN por meio do CROSS JOIN, também conhecido como produto cartesiano. É possível cruzarmos informações de duas ou mais tabelas.

Para facilitar a compreensão a respeito desse tipo de associação, vamos usar as tabelas acima como exemplo. Caso a intenção seja exibir os dados de modo que todos os funcionários tenham todos os cargos e vice-versa. Para isso, devemos usar o CROSS JOIN, como no exemplo a seguir:


SELECT C.NOMECARGO [CARGO], F.NOMEFUNCIONARIO AS [FUNCIONÁRIO], F.SALARIOFUNCIONARIO AS [SALÁRIO]
FROM CARGO AS C
CROSS JOIN FUNCIONARIO AS F
ORDER BY 1

O resultado será o seguinte:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

Conseguimos o mesmo resultado usando a seguinte sintaxe:


SELECT C.NOMECARGO [CARGO], F.NOMEFUNCIONARIO AS [FUNCIONÁRIO], F.SALARIOFUNCIONARIO AS [SALÁRIO]
FROM CARGO AS C, FUNCIONARIO AS F
ORDER BY 1

Observação: Os tipos de associações mais usados são o INNER JOIN e LEFT JOIN, mas é importante conhecer todas as possibilidades de junção entre tabelas.

Usando os comandos UPDATE e DELETE em conjunto

Considerando a tabela Funcionário, criada anteriormente, suponhamos que alguns dados desta tabela serão alterados ou, até mesmo, removidos com base nos dados da tabela criada Vendas, que contém a seguinte estrutura:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

UPDATE

Para nosso exemplo, suponhamos que os funcionários que conseguiram realizar alguma venda devem receber um aumento de 10%. Para isso, primeiro precisamos encontrar quais funcionários atenderam esta condição, usando a seguinte sintaxe:

SELECT F.NOMEFUNCIONARIO AS [FUNCIONÁRIO], F.SALARIOFUNCIONARIO AS [SALÁRIO], 
          V.VALORPEDIDO AS [VALOR]
FROM FUNCIONARIO AS F
INNER JOIN VENDAS AS V ON F.IDFUNCIONARIO = V.IDFUNCIONARIO

Que terá este retorno:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

Agora aplicamos o aumento a estes funcionários, usando a sintaxe a seguir:


UPDATE FUNCIONARIO
SET SALARIOFUNCIONARIO = SALARIOFUNCIONARIO * 1.1
FROM FUNCIONARIO AS F 
INNER JOIN VENDAS AS V ON F.IDFUNCIONARIO = V.IDFUNCIONARIO

A tabela atualizada ficará assim:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

DELETE

Os dados vindos de tabelas associadas podem ser excluídos por meio da cláusula JOIN junto ao comando DELETE.

Como exemplo rápido, vamos excluir todas as vendas feitas por funcionários que recebem salários acima de R$ 3.000,00. Para começar, é recomendável identificar quais são as vendas dos funcionários que recebem o referido salário. Fazemos isso com o seguinte comando:


SELECT V.VALORPEDIDO AS [VALOR], F.SALARIOFUNCIONARIO AS [SALÁRIO], V.IDVENDAS AS [ID DA VENDA]
FROM FUNCIONARIO AS F
INNER JOIN VENDAS AS V ON F.IDFUNCIONARIO = V.IDFUNCIONARIO
WHERE F.SALARIOFUNCIONARIO > 3000.00

Que nos retorna a tabela abaixo:

INNER JOIN, LEFT JOIN e RIGHT JOIN no SQL Server

Para excluirmos a venda acima, é só usarmos o seguinte código:


DELETE VENDAS
FROM FUNCIONARIO AS F 
INNER JOIN VENDAS AS V ON F.IDFUNCIONARIO = V.IDFUNCIONARIO
WHERE F.SALARIOFUNCIONARIO > 3000.00

Com isso, temos exemplos práticos de uso da cláusula JOIN em suas diversas formas que, como vimos, nos permite explorar a associação entre tabelas afim de obter a informação desejada a partir do cruzamento dos dados.

Confira também