Olá galera o/

Hoje irei fazer a atualização de uma postagem que fiz a 6 anos atrás sobre as cláusula JOIN, explicando cada tipo. Como tudo na área de TI se atualiza, resolvi dar um UPGRADE nesta postagem. Hoje vamos repaginar essa postagem e deixa-la mais completa possível.

Passo a passo da postagem:

  1. Modelar um negócio (Modelo Conceitual e Lógico);
  2. Criar o modelo físico no SQL Server ou Azure SQL Database;
  3. Inserir dados nas tabelas do modelo;
  4. Explicar os tipos de Joins e exemplifica-los;
  5. Vídeo explicando os processos anteriores.

Modelo de negócios:

A Loja XYZ deseja informatizar suas operações, visando melhorar o gerenciamento das informações. 

Em uma entrevista com o gerente, o mesmo informou que era necessário ter os seguintes cadastros:

1 - Todos os seus clientes, armazenando informações como: código do cliente, CPF, sexo,  data nascimento, nome, telefone, e-mail, status do cliente (ativo ou inativo) e endereço. 
2 - Todos os produtos armazenando: código de barras, nome do produto, preço unitário, preço de venda (preço com desconto), quantidade em estoque (ex: 10 unidades), quantidade de itens vendidos, status do produto (ativo ou inativo).
3 - Todas as categorias dos produtos, armazenando: código da categoria, descrição da categoria.
4 - Todos os seus funcionário contendo: matricula, nome, sexo, data nascimento, cpf,  salário, e-mail, telefone, data de admissão, data de demissão, status do funcionário (ativo ou inativo), código do supervisor e cargo. 
5 - Informações dos pedidos (vendas) feitos, contendo: código da nota, data e hora do pedido, status do pedido (entregue = 1, não entregue = nulo, cancelado=0), data e hora de saída para entrega (sempre 1 dia após a data do pedido), data e hora da entrega (geralmente 10 dias após a data de saída) e o valor do frente do pedido.
6 - Informações dos fornecedores dos produtos, contendo: código do fornecedor, nome do fornecedor, telefone, cnpj, status do fornecedor.
7 - Informações da transportadora do pedido, contendo: código da transportadora, nome da transportadora, telefone, cnpj e status.

O gerente também passou algumas regras a serem seguidas para que o processo fique como esperado:

a) Um cliente pode fazer vários pedidos, porém um pedido somente pode pertencer a um cliente
b) Um produto pode estar em vários pedidos, e este pedido pode conter vários produtos
c) Um funcionário com cargo de vendedor pode liberar vários pedidos. Um determinado pedido somente pode ser liberado por um funcionário
d) Um produto pode ter apenas uma categoria. Uma categoria pode estar em diversos produtos.
e) Um fornecedor pode fornecer vários produtos, porém um determinado produto só pode ser fornecido por um único fornecedor.
f) Uma transportadora pode fazer a entrega de vários pedidos, porém um pedido só pode ser entregue por uma única transportadora.
g) Um funcionário com cargo de vendedor só pode ser supervisionado por um funcionário com cargo de supervisor, e este supervisor pode gerenciar vários vendedores.

Primeiro vamos aplicar o processo de normalização dos dados, aonde vamos aplicar as cardinalidades, remover atributos multivalorados e dependências funcionais e parciais, isso tudo seguindo as regras impostas pelo cliente.

Caso precise abaixo seguem as postagens sobre cardinalidade e normalização de dados:

  • Cardinalidade
  • Normalização

Agora vamos entender as regras do cliente e aplicar as regras da normalização:

  • Cardinalidades
    • a) Um cliente pode fazer vários pedidos, porém um pedido somente pode pertencer a um cliente;
      • Cliente 1 x N Pedido. Uma chave de cliente será colocada no pedido.
    • b) Um produto pode estar em vários pedidos, e este pedido pode conter vários produtos;
      • Produto N x N Pedido. Uma nova tabela será criada contendo as chaves do pedido e do produto, além disso, vão existir atributos que dependem da composição das duas chaves. Nesta tabela vamos criar uma chave primaria incremental e deixaremos os atributos de origem penas como chave estrangeira.
    • c) Um funcionário com cargo de vendedor pode liberar vários pedidos. Um determinado pedido somente pode ser liberado por um funcionário;
      • Funcionário 1 x N Pedido. Uma chave de funcionário será colocada no pedido.
    • d) Um produto pode ter apenas uma categoria. Uma categoria pode estar em diversos produtos;
      • Categoria 1 x N Produtos. Uma chave de categoria será colocada no pedido.
    • e) Um fornecedor pode fornecer vários produtos, porém um determinado produto só pode ser fornecido por um único fornecedor.
      • Fornecedor 1 x N Produto. Uma chave de fornecedor será colocada no produto.
    • f) Uma transportadora pode fazer a entrega de vários pedidos, porém um pedido só pode ser entregue por uma única transportadora.
      • Transportadora 1 x N Pedido. Uma chave da transportadora será colocada no produto.
    • g) Um funcionário com cargo de vendedor só pode ser supervisionado por um funcionário com cargo de supervisor, e este supervisor pode gerenciar vários vendedores.
      • Funcionário (Vendedor) N x 1 Funcionário (Supervisor). Será adicionado um atributo de chamado supervisor na tabela funcionário, indicando quem é o chefe daquele funcionário.
  • Dependências
    • Na tabela produto possuímos 2 atributos que não dependem apenas da chave de produto, são eles o preço de venda (preço com desconto) e a quantidade de itens vendidos. Ambos os atributos também necessitam do número do pedido.
      • Preço de venda: É o preço quem um determinado produto foi vendido para um determinado pedido, podendo haver desconto. Ex: o preço unitário do produto é 150 reais, mas para o pedido 001 ele foi vendido por 130 reais.
      • Quantidade de Itens Vendidos: É a quantidade de produtos que eu comprei para uma determinada venda. Ex: Foram comprados 10 itens do produto X para o pedido 001.
    • Estes atributos dependem tanto do código do produto quanto do número da nota, eles serão removidos da tabela produto e colocados na tabela que será criada da relação entre produto e pedido.

Uma vez que aplicamos a normalização dos dados, olhem abaixo como fica nosso modelo conceitual e lógico do banco de dados. Utilizei a ferramenta BRModelo para criar o modelo conceitual e lógico. O BRModelo consegue gerar o modelo físico, porém prefiro fazer a criação das tabelas na “mão”. Vou deixar o arquivo do BRModelo disponível para download.

Uma vez que fizemos o modelo conceitual e lógico, agora vamos implementar o modelo físico dentro do SQL Server ou Azure SQL Database Ok?!. Se você ainda não sabe criar um Azure SQL Database sugiro olhar as postagens abaixo, elas irão te instruir sobre como criar uma conta gratuita ou de estudante do Azure e como criar um banco de dados na nuvem na plataforma do Azure.

  • Azure
    • Criando Conta Gratuita no Azure: >> LINK <<
    • Criando Conta de Estudante no Azure: >> LINK <<
    • Implementando um Azure SQL Database: >> LINK <<

Para nosso exemplo vou criar o banco de dados em uma base local (on-premise). Para cada tabela defini quais os melhores tipos de dados para as colunas, suas constraints e criei uma coluna extra em cada tabela chamada dt_insert_linha. Esta coluna receberá uma restrição do tipo DEFAULT com valor GETDATE(), assim armazenando a data em que o registro foi inserido na tabela. Além disso, vamos criar um diagrama dentro do próprio SQL Server para vermos como ficou a codificação do nosso modelo físico. Abaixo posts sobre tipos de dados, Restrições de Domínio (Constraints) e como fazer um diagramas de banco de dados no SQL Server.

  • Importância dos Tipos de dados: >> LINK <<
  • Constraints: >> LINK <<
  • Fazendo diagrama no SQL Server: >> LINK <<
  • Utilizando o ApexModel para fazer diagrama de dados no SQL Server: >> LINK <<

Abaixo segue script de criação do banco de dados, das tabelas e inserção de dados.

USE MASTER
GO

DROP DATABASE IF EXISTS DB_VENDAS_CONSULTABD
GO

CREATE DATABASE DB_VENDAS_CONSULTABD
GO

USE DB_VENDAS_CONSULTABD
GO


/**/
DROP TABLE IF EXISTS PEDIDO_PRODUTO
GO
DROP TABLE IF EXISTS PRODUTO
GO
DROP TABLE IF EXISTS PEDIDO
GO
DROP TABLE IF EXISTS CLIENTE
GO
DROP TABLE IF EXISTS FUNCIONARIO
GO
DROP TABLE IF EXISTS TRANSPORTADORA
GO
DROP TABLE IF EXISTS FORNECEDOR
GO
DROP TABLE IF EXISTS CATEGORIA
GO



/**************** FUNCIONARIO ****************/
CREATE TABLE FUNCIONARIO (
    func_matricula INTEGER PRIMARY KEY IDENTITY,
    func_nome VARCHAR (50) NOT NULL,
    func_sexo CHAR (1),
    func_datanascimento DATE NOT NULL,
    func_cpf CHAR(11) UNIQUE NOT NULL,
    func_salario SMALLMONEY,
    func_email VARCHAR (25),
    func_telefone VARCHAR(15),
    func_dataadmissao DATE DEFAULT (SYSDATETIME()),
    func_datademissao DATE,
    func_status BIT DEFAULT (1),
	func_cargo VARCHAR (20),
    func_codigosupervisor INTEGER FOREIGN KEY REFERENCES FUNCIONARIO(func_matricula),
    dt_insert_linha SMALLDATETIME DEFAULT (SYSDATETIME())
);
GO

INSERT INTO FUNCIONARIO (func_nome, func_sexo, func_datanascimento, func_cpf, func_salario, func_email, func_telefone, func_dataadmissao, func_datademissao, func_status, func_cargo, func_codigosupervisor )
VALUES ('JOSELITO F. M.', 'M', '1980-05-15', '11122244401', 4560, 'JOSELITOFM@LOJAXYZ.COM','81988880000', '2000-04-11', NULL, 1, 'SUPERVISOR', NULL)

INSERT INTO FUNCIONARIO (func_nome, func_sexo, func_datanascimento, func_cpf, func_salario, func_email, func_telefone, func_dataadmissao, func_datademissao, func_status, func_cargo, func_codigosupervisor )
VALUES   ('DIANA S. S.', 'F', '1990-12-02', '11122244402', 1800, 'DIANASS@LOJAXYZ.COM','21988880001', '2010-06-06', NULL, 1, 'VENDEDOR', 1)
		,('LUCAS L. S.', 'M', '1995-09-15', '11122244403', 1900, 'LUCASLS@LOJAXYZ.COM','83988880002', '2019-07-01', DATEADD(DAY,1,GETDATE()), 0, 'VENDEDOR', 1)

INSERT INTO FUNCIONARIO (func_nome, func_sexo, func_datanascimento, func_cpf, func_salario, func_email, func_telefone, func_cargo, func_codigosupervisor )
VALUES ('LUCIANA G. R.', 'F', '2000-05-09', '11122244404', 1600, 'LUCIANAGR@LOJAXYZ.COM','21988880003', 'VENDEDOR', 1)


/**************** TRANSPORTADORA ****************/
CREATE TABLE TRANSPORTADORA (
    transp_codigo INTEGER PRIMARY KEY IDENTITY,
    transp_nome VARCHAR (40) NOT NULL,
    transp_telefone VARCHAR (15),
    transp_cnpj VARCHAR (14) UNIQUE NOT NULL,
    transp_status BIT DEFAULT (1),
	dt_insert_linha SMALLDATETIME DEFAULT (SYSDATETIME())
);
GO

INSERT INTO TRANSPORTADORA(transp_nome, transp_telefone, transp_cnpj, transp_status )
VALUES ('TRANSP ENTREGAS' , '11988887777' , '1122233344455' , 1), ('SPEED ENTREGAS' , '81999991111' , '2233344455566' , 1),
		('RAPIDINHO ENTREGAS' , '31911112222' , '3344455566677' , 1),('LTS DEVILERY' , '51933336666' , '4455566677788' , 1),
		('SUPER RAPIDO ENTREGAS' , '21933334444' , '5566677788899' , 0),('GO ENTREGAS LTDA' , '82922221111' , '6677788899911' , 1),
		('RUNNING DELIVERY' ,  '83955556666', '7788899911122' , 1),('BK FASTER DELIVERY' , '61955557777' , '8899911122233' , 0)
GO


/**************** FORNECEDOR ****************/
CREATE TABLE FORNECEDOR (
    forn_codigo INTEGER PRIMARY KEY IDENTITY,
    forn_nome VARCHAR (40) NOT NULL,
    forn_telefone VARCHAR (15),
    forn_cnpj VARCHAR(14) UNIQUE NOT NULL,
    forn_status BIT DEFAULT (1),
	dt_insert_linha SMALLDATETIME DEFAULT (SYSDATETIME())
);
GO

INSERT INTO FORNECEDOR(forn_nome, forn_telefone, forn_cnpj, forn_status )
VALUES ('SAMSUNG' , '11977778888' , '5511222333444' , 1), ('ABC MATERIAIS ESPORTIVOS' , '81111199999' , '6622333444555' , 0),
		('LG' , '31922221111' , '7733444555666' , 1),('DELL' , '51966663333' , '8844555666777' , 1),
		('JBL' , '21944443333' , '9955666777888' , 1),('PIRELLI' , '82911112222' , '1166777888999' , 1),
		('PET PRODUTOS LTDA' ,  '83966665555', '2277888999111' , 1),('FITNESS EQUIPAMENTOS LTDA' , '61977775555' , '3388999111222' , 0),
		('BRASTEMP' , '64977775555' , '3388999111333' , 1), ('MONDIAL' , '69977775555' , '3388999111444' , 1)
GO

/**************** CATEGORIA ****************/
CREATE TABLE CATEGORIA (
    categ_codigo INTEGER PRIMARY KEY IDENTITY,
    categ_descricao VARCHAR (20) NOT NULL,
	dt_insert_linha SMALLDATETIME DEFAULT (SYSDATETIME())
);
GO

INSERT INTO CATEGORIA(categ_descricao)
VALUES ('INFORMATICA'),('CELULAR'),
	   ('ELETRONICO'),('MOVEL'),
	   ('PRODUTOS IMPORTADOS'),('ELETRODOMESTICOS'),
	   ('BRINQUEDOS'),('VESTUARIO'),
	   ('AUTOMOTIVO'),('LAZER'),
	   ('SAÚDE'),('PET')

GO

/**************** CLIENTE ****************/
CREATE TABLE CLIENTE (
    cli_codigo INTEGER PRIMARY KEY IDENTITY,
    cli_nome VARCHAR (30),
	cli_sexo CHAR (1),
    cli_cpf CHAR(11) UNIQUE NOT NULL,
    cli_datanascimento DATE NOT NULL,
    cli_endereco VARCHAR (100) NOT NULL,
    cli_telefone VARCHAR (15),
    cli_email VARCHAR (30),
    cli_status BIT DEFAULT (1),
	dt_insert_linha SMALLDATETIME DEFAULT (SYSDATETIME())
);
GO

INSERT INTO CLIENTE(cli_nome , cli_sexo, cli_cpf ,cli_datanascimento ,cli_endereco ,cli_telefone ,cli_email ,cli_status)
VALUES ('MARIA J. S.', 'F','11122233311','1990-10-10','RUA DAS FLORES, N 50, RECIFE/PE','81999998811','MARIAJS@EMAIL.COM',1 ),
	   ('FABIO M. F.', 'M','11122233322','1986-02-25','RUA DOS OPERARIOS, N 44, PAULISTA/PE','81999998822','FABIOMF@EMAIL.COM',0 ),
	   ('MARI S. R.', 'F','11122233333','1979-04-15','RUA DOS ENCANTOS, N 1456, SÃO PAULO/SP','11999998833','MARISR@EMAIL.COM',1 ),
	   ('JEAN N. F.', 'M','11122233344','1987-06-06','AVENIDA DOS AMIGOS , N 9985, RIO DE JANEIRO/RJ','21999998844','JEANNF@EMAIL.COM',1 ),
	   ('EDUARDO G. T.', 'M','11122233355','1995-08-22','RUA DOS MILAGRES, N 04, CABO BRANCO/PB','83999998855','EDUARDOGT@EMAIL.COM',0 ),
	   ('LUIZ T. S.', 'M','11122233366','1991-11-23','RUA DAS ARVORES, N 775, RECIFE/PE','81999998866','LUIZTS@EMAIL.COM',1 ),
	   ('CAMILA M. T.', 'F','11122233377','1992-12-12','RUA DAS MARGARIDAS, N 3333, PORTO ALEGRE/RS','51999998877','CAMILAMT@EMAIL.COM',1 ),
	   ('JULIANA B. C.', 'F','11122233388','1993-03-10','RUA DOS PINHAIS, N 9987, SÃO JOSÉ DOS PINHAIS/PR','41999998888','JULIANABC@EMAIL.COM',1 ),
	   ('DEBORA G. S.', 'F','11122233399','1992-07-13','RUA DAS MARIAS, N 7784, ITAJAI/SC','47999998899','DEBORAGS@EMAIL.COM',0 ),
	   ('ROGER T. F.', 'M','11122233310','1999-09-29','RUA DA FEIRA, N 4410, BRASILIA/DF','61999998810','ROGERTF@EMAIL.COM',1 )
GO

/**************** PEDIDO ****************/
CREATE TABLE PEDIDO (
    ped_numero INTEGER PRIMARY KEY IDENTITY,
    ped_datahora SMALLDATETIME DEFAULT (SYSDATETIME()),
    ped_datahorasaida SMALLDATETIME,
    ped_datahoraentrega SMALLDATETIME,
    ped_valorfrete SMALLMONEY,
	ped_status BIT DEFAULT (1),
    fk_cli_codigo INTEGER FOREIGN KEY REFERENCES CLIENTE(cli_codigo),
    fk_func_matricula INTEGER FOREIGN KEY REFERENCES FUNCIONARIO(func_matricula),
    fk_transp_codigo INTEGER FOREIGN KEY REFERENCES TRANSPORTADORA(transp_codigo),
	dt_insert_linha SMALLDATETIME DEFAULT (SYSDATETIME())
);
GO


INSERT INTO PEDIDO (ped_datahora , ped_datahorasaida, ped_datahoraentrega ,ped_valorfrete ,ped_status ,fk_cli_codigo,fk_func_matricula, fk_transp_codigo)
VALUES  ('2020-10-10', '2020-10-11', '2020-10-21', 45.5, 1, 3, 2, 2)
		,('2020-05-05', '2020-05-06', '2020-05-26', 5.50, 1, 3, 2, 3)
		,('2020-01-20', '2020-01-21', '2020-02-04', 0.00, 1, 3, 2, 2)

INSERT INTO PEDIDO (ped_datahorasaida, ped_datahoraentrega ,ped_valorfrete ,ped_status ,fk_cli_codigo,fk_func_matricula, fk_transp_codigo)
VALUES	 (DATEADD(day,1,getdate()), NULL, 12.88, NULL, 4, 2, 7)
		,(DATEADD(day,1,getdate()), NULL, 77.5, 0, 5, 3, 5)
		,(DATEADD(day,1,getdate()), DATEADD(DAY,10,DATEADD(day,1,getdate())), 4.45, 1, 2, 4, 6)
		,(DATEADD(day,1,getdate()), DATEADD(DAY,10,DATEADD(day,1,getdate())), 0.00, 1, 8, 4, 2)


/**************** PRODUTO ****************/
CREATE TABLE PRODUTO (
    prod_codigo INTEGER PRIMARY KEY IDENTITY,
    prod_nome VARCHAR (100) NOT NULL,
    prod_precounitario SMALLMONEY NOT NULL,
    prod_quantidadeestoque SMALLINT,
    prod_status BIT DEFAULT (1),
    fk_categ_codigo INTEGER FOREIGN KEY REFERENCES CATEGORIA (categ_codigo),
    fk_forn_codigo INTEGER FOREIGN KEY REFERENCES FORNECEDOR(forn_codigo),
	dt_insert_linha SMALLDATETIME DEFAULT (SYSDATETIME())
);
GO

INSERT INTO PRODUTO(prod_nome , prod_precounitario, prod_quantidadeestoque ,prod_status ,fk_categ_codigo ,fk_forn_codigo)
VALUES ('MONITOR CURVADO 24 POLEGADAS', 980.00, 15, 1, 1, 1),
	   ('FONE BLUETOOTH JBL', 320.00, 6, 1, 1, 5),
	   ('NOTEBOOK DELL I7 8GB RAM 128 SSD 1TB HDD', 4000.00, 50, 1, 1, 4),
	   ('PNEU ARO 14', 200.00, 20, 1, 9, 6),
	   ('PNEU ARO 17', 300.00, 12, 0, 9, 6),
	   ('COLEIRA PEITORAL PARA CÃES', 99.50, 35, 1, null, 7),
	   ('KIT 10 PLACAS DE TATAME', 142.70, 700, 1, 10, 2),
	   ('SMARTPHONE LG K61', 1399, 4, 1, 4, 3),
	   ('SMART TV LG 55" 4K UHD WIFI HDR INTELIGÊNCIA ARTIFICIAL THINQ', 3099.00, 7, 1, 3, 3),
	   ('FRITADEIRA ELÉTRICA SEM ÓLEO – AIR FRYER MONDIAL AF-34 3,2L 1270W PRETA 127V', 389.99, 11, 1, 6, 10),
	   ('ASPIRADOR ROBÔ MONDIAL RB-01 FAST CLEAN BIVOLT', 520.00, 10, 1, 6, 10),
	   ('LAVADORA DE ROUPAS BRASTEMP 12KG BWK12 BRANCA', 1699.99, 3, 1, 6, 9),
	   ('GELADEIRA/REFRIGERADOR BRASTEMP FROST FREE BRM44 375 LITROS - EVOX', 2399.89, 9, 1, 6, 9)



/**************** PEDIDO_PRODUTO ****************/
CREATE TABLE PEDIDO_PRODUTO (
	pedprod_codigo INTEGER PRIMARY KEY IDENTITY,
	pedprod_precovenda SMALLMONEY NOT NULL,
    pedprod_quantidadeitensvendidos SMALLINT DEFAULT (1),
    fk_ped_numero INTEGER FOREIGN KEY REFERENCES PEDIDO (ped_numero),
    fk_prod_codigo INTEGER FOREIGN KEY REFERENCES PRODUTO (prod_codigo),
	dt_insert_linha SMALLDATETIME DEFAULT (SYSDATETIME())
);
GO

INSERT INTO PEDIDO_PRODUTO (pedprod_precovenda, pedprod_quantidadeitensvendidos, fk_ped_numero, fk_prod_codigo)
VALUES (3500.00, 1, 3, 3),
	   (950.00, 1, 2, 1),
	   (300.00, 2, 1, 2),

	   (2000.00, 1, 4, 13),

	   (1699.99, 1, 5, 12),

	   (420.99, 3, 6, 11),
	   (300.00, 3, 6, 10),

	   (1000.00, 1, 7, 8),
	   (3000.00, 1, 7, 9),
	   (140.00, 2, 7, 7)

Agora que temos nossas tabelas estão criadas e com registros, vamos explicar cada tipo de JOIN existente e exemplifica-los com cenários aonde vamos realizar junção de 2 ou mais tabelas. Lembrem-se que, o fluxo de ligação das tabelas no JOIN é o mesmo em que os dados foram modelados no modelo conceitual e lógico. Além disso os Joins é baseado na teoria dos conjuntos.

O que são os JOINs?

A cláusula JOIN é utilizada para realizar a combinação das tabelas do banco de dados. Toda essa combinação é baseada no processo de modelagem do negócio. A ligação das tabelas é geralmente feita através dos campos de chave primária e chave estrangeira. Os JOINs possuem uma cláusula chamada ON, que é responsável iniciar a combinação dos campos utilizados na junção.

Sintaxe 2 Tabelas:
SELECT <COLUNAS>
FROM TABELA_A
JOIN  TABELA_B
ON TABELA_A.PK = TABELA_B.FK

Sintaxe 3 ou mais Tabelas:
SELECT <COLUNAS>
FROM TABELA_A
JOIN  TABELA_B
ON TABELA_A.PK_A = TABELA_B.FK_A
JOIN TABELA_C
ON TABELA_A.PK_A = TABELA_C.FK_A
  • Tipos de Join:
    • JOIN ou INNER JOIN (Intersecção)
    • LEFT OUTER JOIN OU LEFT JOIN
    • LEFT JOIN EXCLUSIVO
    • RIGHT OUTER JOIN ou RIGHT JOIN
    • RIGHT JOIN EXCLUSIVO
    • FULL OUTER JOIN ou FULL JOIN
    • FULL JOIN EXCLUSIVO
    • CROSS JOIN (Prod. Cartesiano)
    • SELF JOIN (Auto-relacionamento)

JOIN ou INNER JOIN: Tipo de join que retorna os dados apenas quando existe correspondência entre as duas ou mais tabelas relacionadas, ou seja, exiba somente o que é correspondente entre A e B. O INNER JOIN é a intersecção da teoria dos conjuntos. Obs.: Se você escrever apenas a palavra JOIN significa que você esta realizando um INNER JOIN, a palavra INNER fica implícita (ocultada) quando não declarada.

Cenário 1 – Junção de 2 tabelas: Criar uma consulta que retorne apenas clientes que fizeram pedidos e pedidos que tenham tenham clientes. Nesta consulta deve conter o código do cliente, o nome do cliente, número e data/hora do pedido. De acordo com nossa modelagem a tabela cliente se relaciona com a tabela pedido através do campo fk_cli_codigo contido na tabela pedido. Na tabela de cliente existem 10 clientes, porém apenas 5 deles fizeram pedidos, os que não fizeram não serão retornados nesta consulta.

select
     c.cli_codigo,
     c.cli_nome,
     p.ped_numero,
     p.ped_datahora
 from cliente as c
 inner join pedido as p
     on c.cli_codigo = p.fk_cli_codigo

Cenário 2 – Junção de 3 tabelas: Criar uma consulta que retorne dados dos clientes que fizeram pedidos e pedidos que tenham tenham clientes, além disso, também traga pedidos que possuem transportadora e transportadoras que entregaram pedidos. Nesta consulta deve conter o código do cliente, o nome do cliente, número e data/hora do pedido, código, nome e cnpj da transportadora responsável pelo pedido. De acordo com nossa modelagem a tabela cliente se relaciona com a tabela pedido através do campo fk_cli_codigo contido na tabela pedido e a tabela transportadora se relaciona com o pedido através do campo fk_transp_codigo.

select
     c.cli_codigo,
     c.cli_nome,
     p.ped_numero,
     p.ped_datahora,
     t.transp_codigo,
     t.transp_nome,
     t.transp_cnpj
 from cliente as c
 inner join pedido as p
     on c.cli_codigo = p.fk_cli_codigo
 inner join transportadora as t
     on p.fk_transp_codigo = t.transp_codigo

Cenário 3 – Junção de 4 tabelas: Criar uma consulta que retorne dados dos clientes que fizeram pedidos e pedidos que tenham tenham clientes, além disso, também traga os produtos contidos no pedido. Nesta consulta deve conter o código do cliente, o nome do cliente, número e data/hora do pedido, código, nome, preço unitário, preço de venda, quantidade comprada e o subtotal daquele produto, ou seja, (preço de venda * quantidade de itens vendidos). De acordo com nossa modelagem a tabela cliente se relaciona com a tabela pedido através do campo fk_cli_codigo contido na tabela pedido, o pedido e o produto se relacionam através da tabela pedido_produto, que contém os campos fk_prod_codigo (produto) e fk_ped_numero (pedido).

select
	c.cli_codigo,
	c.cli_nome,
	p.ped_numero,
	p.ped_datahora,
	prd.prod_codigo,
	prd.prod_nome,
	prd.prod_precounitario,
	pp.pedprod_precovenda,
	pp.pedprod_quantidadeitensvendidos,
	(pp.pedprod_precovenda * pp.pedprod_quantidadeitensvendidos) as subtotal
from cliente as c
inner join pedido as p
	on c.cli_codigo = p.fk_cli_codigo
inner join pedido_produto as pp
	on pp.fk_ped_numero = p.ped_numero
inner join produto as prd 
	on pp.fk_prod_codigo = prd.prod_codigo

LEFT JOIN ou LEFT OUTER JOIN: Tipo de join que retorna todos os dados da tabela da esquerda (tabela de cima) mesmo que não exista correspondência com a tabela da direita (tabela abaixo do left join), ou seja, exiba todos os registros de A mesmo que não exista correspondência com B. Os valores que não são correspondentes da tabela da direita (B) ficam com o valor NULL. Se você escrever apenas a palavra LEFT JOIN significa que você esta realizando um LEFT OUTER JOIN, a palavra OUTER fica implícita (ocultada) quando não declarada.

Cenário: Criar uma consulta que retorne todos os clientes que fizeram pedidos e os que não fizeram pedidos. Nesta consulta deve conter o código do cliente, o nome do cliente, número e data/hora do pedido. De acordo com nossa modelagem a tabela cliente se relaciona com a tabela pedido através do campo fk_cli_codigo. Percebam que para os clientes que não realizaram pedidos, os campos ped_numero e ped_datahora ficaram nulos.

select
      c.cli_codigo,
      c.cli_nome,
      p.ped_numero,
      p.ped_datahora
  from cliente as c
  left join pedido as p
      on c.cli_codigo = p.fk_cli_codigo

LEFT JOIN EXCLUSIVO: Segue os mesmos conceitos do LEFT JOIN, porém filtramos quando a chave da tabela da direita (B) esta nula, ou seja, apenas retorne registros da tabela da esquerda (A) que não tem correspondência com a tabela da direita.

Cenário: Criar uma consulta que retorne todos os clientes que não fizeram pedidos. Nesta consulta deve conter o código do cliente, o nome do cliente, número e data/hora do pedido. De acordo com nossa modelagem a tabela cliente se relaciona com a tabela pedido através do campo fk_cli_codigo. Percebam que ele retornará apenas os clientes que nunca fizeram pedidos.

select
      c.cli_codigo,
      c.cli_nome,
      p.ped_numero,
      p.ped_datahora
  from cliente as c
  left join pedido as p
      on c.cli_codigo = p.fk_cli_codigo
 where p.fk_cli_codigo is null

RIGHT JOIN ou RIGHT OUTER JOIN: Tipo de join que retorna todos os dados da tabela da direita (tabela de abaixo do right) mesmo que não exista correspondência com a tabela da esquerda (tabela acima do right join), ou seja, exiba todos os registros de B mesmo que não exista correspondência com A. Os valores que não são correspondentes da tabela da esquerda (A) ficam com o valor NULL. Se você escrever apenas a palavra RIGHT JOIN significa que você esta realizando um RIGHT OUTER JOIN, a palavra OUTER fica implícita (ocultada) quando não declarada.

Cenário: Criar uma consulta que retorne todos as transportadoras que fizeram ou não transporte de pedidos. Nesta consulta deve conter o número e data/hora do pedido, código e nome da transportadora. De acordo com nossa modelagem a tabela transportadora se relaciona com a tabela pedido através do campo fk_transp_codigo. Temos duas observações, primeiro, a tabela após o FROM é a tabela PEDIDO, ou seja, a tabela da esquerda e a tabela da direita é a transportadora, segundo, para as transportadoras que não fizeram o transporte de pedidos, os campos ped_numero e ped_datahora ficaram nulos.

select
      p.ped_numero,
      p.ped_datahora,
      t.transp_codigo,
      t.transp_nome
  from pedido as p
  right join transportadora as t
      on p.fk_transp_codigo = t.transp_codigo

RIGHT JOIN EXCLUSIVO: Segue os mesmos conceitos do RIGHT JOIN, porém filtramos quando a chave da tabela da esquerda (A) esta nula, ou seja, apenas retorne registros da tabela da direita (B) que não tem correspondência com a tabela da esquerda.

Cenário: Criar uma consulta que retorne apenas as transportadoras que não transportaram pedidos. Nesta consulta deve conter o número e data/hora do pedido, código e nome da transportadora. De acordo com nossa modelagem a tabela transportadora se relaciona com a tabela pedido através do campo fk_transp_codigo. Percebam que ele retornará apenas as transportadoras que nunca fizeram transporte de pedidos.

select
      p.ped_numero,
      p.ped_datahora,
      t.transp_codigo,
      t.transp_nome
  from pedido as p
  right join transportadora as t
      on p.fk_transp_codigo = t.transp_codigo
 where p.fk_transp_codigo is null

FULL JOIN ou FULL OUTER JOIN: Tipo de join que retorna os dados que tiveram ou não correspondência tanto da tabela da esquerda quanto da direita, ou seja, ele vai retornar todos que tem correspondência (INNER), e também os que não tiveram da esquerda (LEFT) e direita(RIGHT). Os valores que não são correspondentes ficam com o valor NULL. Se você escrever apenas a palavra FULL JOIN significa que você esta realizando um FULL OUTER JOIN, a palavra OUTER fica implícita (ocultada) quando não declarada.

Cenário: Criar uma consulta que retorne os dados dos produtos que possuem ou não categoria e categorias que tem ou não produtos vinculados. Nesta consulta deve conter o código, nome, preço unitário e quantidade em estoque do produto e da categoria código e nome da mesma. De acordo com nossa modelagem a tabela categoria se relaciona com a tabela produto através do campo fk_categ_codigo. Observem que existe um produto que não teve a categoria informada no momento do INSERT. Para os produtos que não tem categoria os campos de categoria ficam nulos, e para as categorias que não possuem produtos, os campos do produto ficam nulos.

select 
	p.prod_codigo,
	p.prod_nome,
	p.prod_precounitario,
	p.prod_quantidadeestoque,
	c.categ_codigo,
	c.categ_descricao
from produto as p
full join categoria as c
	on p.fk_categ_codigo = c.categ_codigo

FULL JOIN EXCLUSIVO: Segue os mesmos conceitos do FULL JOIN, porém filtramos quando as chaves da tabelas da esquerda e direita são nulas, ou seja, apenas retorne registros das tabelas da esquerda e direta que não possuem correspondência de chave (Diferença da intersecção).

Cenário: Criar uma consulta que retorne os dados dos produtos que não possuem categoria e categorias que não produtos vinculados. Nesta consulta deve conter o código, nome, preço unitário e quantidade em estoque do produto e da categoria código e nome da mesma. De acordo com nossa modelagem a tabela categoria se relaciona com a tabela produto através do campo fk_categ_codigo. Para os produtos que não tem categoria os campos de categoria ficam nulos, e para as categorias que não possuem produtos, os campos do produto ficam nulos.

select 
     p.prod_codigo,
     p.prod_nome,
     p.prod_precounitario,
     p.prod_quantidadeestoque,
     c.categ_codigo,
     c.categ_descricao
 from produto as p
 full join categoria as c
     on p.fk_categ_codigo = c.categ_codigo
 where p.fk_categ_codigo is null
 or c.categ_codigo is null

CROSS JOIN: Tipo de JOIN que combina os dados das duas tabelas formando um produto cartesiano. Este tipo de JOIN não utiliza a clausula ON. Ele faz uma combinação dos registros de uma tabela com outra, ou seja, se a tabela A tem 4 registros e a tabela B possui 3, ele vai realizar um relacionamento de todos os itens de A como Todos de B e vice-versa, assim, retornando 12 registros. Muito parecido com uma Matriz.

Cenário: Criar uma consulta que retorne um produto cartesiano entre produto e transportadora. Nesta consulta deve conter o código e nome do produto e da transportadora código e nome da mesma. Temos duas observações no CROSS JOIN, primeiro, não utilizamos a cláusula ON, então, podemos ligar duas tabelas que não possuem nenhum relacionamento lógico no modelo. Segundo, ele vai multiplicar 13 registros da tabela produto com 8 registros da tabela transportadora, assim, resultando em 104 combinações desses dados.

select 
     p.prod_codigo,
     p.prod_nome,
     t.transp_codigo,
     t.transp_nome
 from produto as p
 cross join transportadora as t

SELF JOIN: É um CONCEITO de JOIN e não um comando propriamente dito. Ele é caracterizado na modelagem como auto relacionamento, ou seja, a tabela se relacionando com ela mesma. Pode-se utilizar qualquer tipo de JOIN. Ex.: Em uma empresa por exemplo, um funcionário com cargo de gerente ou coordenador pode chefiar um outro funcionário com cargo de analista ou estagiário.

Cenário 1 : Criar uma consulta que retorne todos os funcionários que possuem supervisores e supervisores que supervisionam funcionários. Nesta consulta deve conter o matricula, nome, cargo do funcionário, além do nome e cargo do supervisor dos funcionários. Para replicar este cenário vamos fazer um INNER JOIN da tabela funcionário com ela mesma, ligando o campo func_matricula com o campo func_codigosupervisor. A primeira tabela de funcionário vamos chamar colocar um alias chamado FUNC e será responsável por trazer os dados dos funcionários chefiados, a outra tabelas vai receber o alias SUP, que retornará os dados do funcionário que é supervisor. A ligação será a seguinte func.func_codigosupervisor com sup.func_matricula, ou seja, quando o código do supervisor do funcionário chefiado for igual ao código de matriculado funcionário que é supervisor.

select 
     func.func_matricula as 'Matricula Funcionário',
     func.func_nome as 'Nome Funcionário',
     func.func_cargo as 'Cargo Funcionário',
     sup.func_nome as 'Nome Supervisor',
     sup.func_cargo as 'Cargo Supervisor'
 from funcionario as func
 inner join funcionario as sup
 on func.func_codigosupervisor = sup.func_matricula

Cenário 2 : Criar uma consulta que retorne todos os funcionários que possuem ou não supervisores. Nesta consulta deve conter o matricula, nome, cargo do funcionário, além do nome e cargo do supervisor dos funcionários. Para replicar este cenário vamos fazer um LEFT JOIN da tabela funcionário com ela mesma, ligando o campo func_matricula com o campo func_codigosupervisor. A primeira tabela de funcionário vamos chamar colocar um alias chamado FUNC e será responsável por trazer os dados dos funcionários chefiados, a outra tabelas vai receber o alias SUP, que retornará os dados do funcionário que é supervisor. A ligação será a seguinte func.func_codigosupervisor com sup.func_matricula, ou seja, quando o código do supervisor do funcionário chefiado for igual ao código de matriculado funcionário que é supervisor. Percebam que um dos funcionários que possui cargo de supervisor não possui chefe, ou seja, nos campos referentes ao supervisor para esse funcionário em específico, o valor NULL será atribuído.

select 
     func.func_matricula as 'Matricula Funcionário',
     func.func_nome as 'Nome Funcionário',
     func.func_cargo as 'Cargo Funcionário',
     sup.func_nome as 'Nome Supervisor',
     sup.func_cargo as 'Cargo Supervisor'
 from funcionario as func
 left join funcionario as sup
 on func.func_codigosupervisor = sup.func_matricula

Abaixo segue um vídeo explicando todo o processo de como criar os Joins:

É isso galera, essa postagem ficou bem longa, porém, esta bem detalhada explicando cada tipo de JOIN com exemplos práticos! Espero que depois dessa postagem sua visão e seu conhecimento tenha sido ampliado sobre como fazer e quais tipos JOIN utilizar. Lembrem-se que, saber desenvolver consultas com JOINs são um dos requisitos mais importantes para quem trabalha da área de dados, então pratiquem bastante para pegar a prática.

Para quem quer estudar:

  • Para a Certificação Microsoft MTA Database Fundamentals
    • Segue o link do curso na Udemy. >> LINK <<
  • Sobre Bancos da Dados no Azure
    • Segue o link do curso na Udemy. >> LINK <<

Não se esqueçam de avaliar esta postagem através da ESTRELAS abaixo das redes sociais, isso vai me ajudar muito a melhorar as postagens.

Quem quiser mandar comentários, sugestões, criticas e complementos, fiquem a vontade, pois feedbacks positivos ou negativos engradecem meu conhecimento para que possa melhorar as postagem para vocês.

Até a próxima o/

Acessem nossas Redes Sociais: