A cláusula JOIN é uma das ferramentas mais essenciais e amplamente utilizadas no SQL, utilizada para combinar registros de duas ou mais tabelas e gerar uma tabela resultante com as relações explícitas entre elas. Para quem está começando com SQL, o JOIN pode parecer um bicho de sete cabeças, mas neste artigo desmitificaremos este monstro, explorando seus diferentes tipos, cada um adequado para diferentes cenários.
A Teoria dos Conjuntos é um ramo da matemática que estuda o agrupamento de elementos que possuem características em comum, chamados de conjuntos. Nela, são estudadas relações importantes entre estes conjuntos e as operações que podem ser realizadas com eles, como união, intersecção e diferença.
Os joins baseiam-se fortemente na Teoria dos Conjuntos, e as operações desta cláusula são literalmente as operações de união, diferença e intersecção, na forma da sintaxe do SQL. Por meio delas, podemos extrair resultados que fornecem informações valiosas para um negócio, estudo, etc.
Para começo de conversa, devemos entender os conceitos de chave primária e chave estrangeira para poder compreender o funcionamento do JOIN. É através delas que conseguimos identificar os elementos comuns das tabelas e fazer as relações entre eles.
A chave primária é a coluna responsável por identificar de forma distinta cada uma das linhas da tabela. Possui um valor único que não pode ser repetido, geralmente sendo uma coluna de ID.
A chave estrangeira, por sua vez, está intimamente ligada à chave primária e é responsável por relacionar os campos de uma segunda tabela às suas respectivas chaves primárias da tabela principal.
Como podemos ver na figura acima, a coluna “IDDepartamento” da tabela “Funcionarios” está relacionada à mesma coluna “IDDepartamento” da tabela “Departamentos”, permitindo assim indicar a qual departamento cada um dos funcionários pertencem, por meio da chave estrangeira.
Considerando o exemplo anterior, temos uma tabela com informações que não se repetem, e outra com informações repetidas. Em um banco de dados, encontraremos tabelas destes dois tipos, classificadas como tabela fato e tabela dimensão.
A tabela dimensão contém todas as informações e características relacionadas ao elemento representado. No nosso exemplo, a tabela dimensão seria a tabela de departamentos, que contém o nome de todos os departamentos de uma empresa. Repare que, na tabela dimensão, as informações não podem se repetir, e seus registros são utilizados como chave primária.
A tabela fato registra todas as ocorrências do elemento representado, podendo conter milhares de linhas e informações repetidas. Ela extrapola as informações e características contidas na tabela dimensão para cada uma das ocorrências registradas, sendo assim, as informações definidas na tabela dimensão são reaproveitadas.
Repare que aqui temos uma tabela que registra os funcionários de uma empresa, e outra que registra as contribuições de cada funcionário. A tabela dimensão contém apenas os funcionários existentes na empresa, e a tabela fato referencia-os para cada contribuição realizada.
Agora que já entendemos a teoria, podemos partir para a prática. Criaremos três tabelas: uma de funcionários, outra de departamentos, e uma última de contribuições de cada funcionário. Com as tabelas criadas, inseriremos as informações.
sql1-- Criação da tabela de funcionários 2CREATE TABLE Funcionarios ( 3 IDFuncionario INT PRIMARY KEY, 4 PrimeiroNome NVARCHAR(50), 5 UltimoNome NVARCHAR(50), 6 IDDepartamento INT 7); 8-- Inserindo dados na tabela de funcionários 9INSERT INTO Funcionarios (IDFuncionario, PrimeiroNome, UltimoNome, IDDepartamento) 10VALUES 11 (1, 'Charles', 'Babbage', 2), 12 (2, 'Alan', 'Turing', 1), 13 (3, 'Ada', 'Lovelace', 1), 14 (4, 'Timothy', 'Berners-Lee', 3), 15 (5, 'Gabriel', 'Oliveira', 1), 16 (6, 'Juninho', 'Portugal', NULL); 17-- Criação da tabela de departamentos 18CREATE TABLE Departamentos ( 19 IDDepartamento INT PRIMARY KEY, 20 NomeDepartamento NVARCHAR(50) 21); 22-- Inserindo dados na tabela de departamentos 23INSERT INTO Departamentos (IDDepartamento, NomeDepartamento) 24VALUES 25 (1, 'Depto. de Software'), 26 (2, 'Depto. de Hardware'), 27 (3, 'Depto. de Redes'); 28-- Criação da tabela de contribuições 29CREATE TABLE Contribuicoes ( 30 IDContribuicao INT PRIMARY KEY, 31 IDFuncionario INT, 32 Contribuicao NVARCHAR(255) 33); 34-- Inserindo dados na tabela de contribuições 35INSERT INTO Contribuicoes (IDContribuicao, IDFuncionario, Contribuicao) 36VALUES 37 (1, 1, 'Inventor da máquina analítica'), 38 (2, 2, 'Pai da computação moderna'), 39 (3, 2, 'Criador da Máquina de Turing'), 40 (4, 2, 'Desenvolvedor do Teste de Turing'), 41 (5, 3, 'Primeira programadora de computador'), 42 (6, 3, 'Criadora do primeiro algoritmo para uma máquina'), 43 (7, 4, 'Inventor da World Wide Web'), 44 (8, 4, 'Desenvolvedor do primeiro navegador web');
Com as tabelas criadas no banco, podemos começar a estudar cada JOIN.
Os JOINS seguem uma sintaxe básica padrão, que envolve a combinação entre duas tabelas a partir de uma condição específica. Veja abaixo.
sql1SELECT Coluna1, Coluna2, ... 2FROM TabelaA 3[TIPO DE JOIN] TabelaB 4ON TabelaA.Coluna = TabelaB.Coluna;
Na primeira parte, temos um “SELECT FROM” padrão, uma vez que o JOIN é uma cláusula de junção do SELECT.
sql1SELECT Coluna1, Coluna2, ... 2FROM TabelaA
Agora, após o JOIN, você deve especificar qual tabela você deseja relacionar com a primeira.
sql1[TIPO DE JOIN] TabelaB
Por fim, na palavra-chave “ON”, você precisa especificar qual coluna da tabela A tem os elementos em comum com a coluna da tabela B.
sql1ON TabelaA.Coluna = TabelaB.Coluna;
Esta é a estrutura básica de um JOIN. É normal caso ainda não tenha ficado muito claro, pois veremos a seguir como executar o JOIN, na prática.
O INNER JOIN é bastante intuitivo: ele traz apenas as linhas que tem correspondência entre as duas tabelas especificadas, correspondendo à operação de intersecção da teoria de conjuntos (“A ∩ B”). A tabela resultante desta operação trará apenas valores que estão presentes em ambas as tabelas.
No nosso exemplo, usaremos a tabela dimensão “Funcionários”, que tem o registro de todos os funcionários da empresa. Além dela, temos a tabela fato “Contribuições”, que registra todas as contribuições feitas por cada funcionário. Repare abaixo como estas tabelas são.
Para cada contribuição, temos um valor numérico que corresponde ao ID de um funcionário cadastrado na tabela “Funcionarios”. Com o INNER JOIN, podemos trazer este valor em comum nas duas tabelas. Veja abaixo, como fica esta consulta.
sql1SELECT 2 Funcionarios.PrimeiroNome, 3 Funcionarios.UltimoNome, 4 Contribuicoes.Contribuicao 5FROM 6 Funcionarios 7INNER JOIN 8 Contribuicoes ON Funcionarios.IDFuncionario = Contribuicoes.IDFuncionario;
Cada linha da tabela resultante trará o primeiro e último nome correspondente a cada ID, trazendo uma tabela com todas as contribuições, e os respectivos funcionários responsáveis por cada contribuição.
No exemplo anterior, você pode reparar que a consulta não retornou todos os funcionários da empresa. Isto porque estávamos tratando da intersecção entre as duas tabelas. Os funcionários Gabriel Oliveira e Juninho Portugal estão cadastrados na tabela “Funcionarios”, mas não possuem contribuições registradas na tabela “Contribuicoes” e, por esse motivo, não apareceram no resultado. O INNER JOIN trouxe apenas os elementos em comum entre as duas tabelas. Uma vez que vimos isso, fica fácil de entender o FULL JOIN. Ao invés de trazer a intersecção entre as duas tabelas, ele trará a união delas (“A ∩ B”). A consulta ficará como abaixo.
sql1SELECT 2 Funcionarios.PrimeiroNome, 3 Funcionarios.UltimoNome, 4 Contribuicoes.Contribuicao 5FROM 6 Funcionarios 7FULL JOIN 8 Contribuicoes ON Funcionarios.IDFuncionario = Contribuicoes.IDFuncionario;
Repare que ele trará as colunas das duas tabelas que especificamos no SELECT, independente de os registros existirem em ambas. Para os colaboradores que não tem contribuições registradas, as linhas ficarão “NULL”.
Por último, temos o LEFT e RIGHT JOIN. Estamos falando simultaneamente de ambos, por realizarem a mesma operação, mudando apenas um detalhe. Sabemos que “LEFT” é esquerda em inglês, enquanto “RIGHT” é direita. É justamente aí que mora a diferença entre os dois.
O LEFT JOIN traz todos os resultados da tabela à esquerda, e os valores correspondentes na tabela à direita. Ou seja, todos os valores da tabela à direita que também estão presentes na tabela à esquerda serão retornados, ao passo que os demais serão descartados.
O RIGHT JOIN, por sua vez, traz todos os elementos da tabela direita e os correspondentes na tabela à esquerda, descartando os elementos da tabela à esquerda que não tem relação com a tabela à direita. Vamos, então, entender cada um desses dois. Veja as duas tabelas abaixo.
Repare que, na tabela “Funcionarios”, a linha número 6 tem um valor “NULL” na coluna de departamento. Isso fará toda a diferença ao usarmos o LEFT ou RIGHT JOIN. Veja a query abaixo, que executará um RIGHT JOIN.
sql1SELECT 2 Funcionarios.PrimeiroNome, 3 Funcionarios.UltimoNome, 4 Funcionarios.IDDepartamento, 5 Departamentos.NomeDepartamento 6FROM 7 Funcionarios 8RIGHT JOIN 9 Departamentos ON Funcionarios.IDDepartamento = Departamentos.IDDepartamento;
Como a tabela “Funcionarios” foi a primeira a especificarmos na consulta, ela está sendo considerada como a tabela da esquerda. Logo após, especificamos a tabela “Departamentos”, ficando então como a tabela da esquerda. Como o RIGHT JOIN traz todos os elementos em comum da tabela esquerda com a tabela da direita, e descarta os sem relação, o funcionário Juninho Portugal ficará de fora do resultado, por não ter nenhum departamento da tabela de departamentos.
Agora, se utilizarmos o LEFT JOIN, o resultado trará todos os registros da tabela à esquerda, mais os que tem relação na tabela à direita.
sql1SELECT 2 Funcionarios.PrimeiroNome, 3 Funcionarios.UltimoNome, 4 Funcionarios.IDDepartamento, 5 Departamentos.NomeDepartamento 6FROM 7 Funcionarios 8LEFT JOIN 9 Departamentos ON Funcionarios.IDDepartamento = Departamentos.IDDepartamento;
Desta forma, por mais que um elemento da tabela à esquerda não tenha relação com a tabela da direita, ele será trazido na tabela resultante. Veja abaixo.
Neste artigo, exploramos a cláusula JOIN no SQL, focando nos tipos INNER JOIN, LEFT JOIN e RIGHT JOIN, e como eles se relacionam com as operações de conjuntos na matemática. O INNER JOIN retorna apenas as linhas com correspondências em ambas as tabelas, similar à intersecção na teoria dos conjuntos. O LEFT JOIN retorna todas as linhas da tabela à esquerda e suas correspondências na tabela à direita, preenchendo com "NULL" onde não há correspondências. O RIGHT JOIN funciona de maneira semelhante ao LEFT JOIN, mas prioriza a tabela à direita. Essas operações são fundamentais para combinar dados de múltiplas tabelas de forma eficiente e precisa, essencial para tarefas de análise e manipulação de dados.