kb.erickguedes.com
SQL: Domínio de Bancos Relacionais

Joins — Juntando Tabelas

Aula 2 de 8

Relacionamentos

-- Tabelas para os exemplos
CREATE TABLE clientes (
    id SERIAL PRIMARY KEY,
    nome VARCHAR(100) NOT NULL
);

CREATE TABLE pedidos (
    id SERIAL PRIMARY KEY,
    cliente_id INTEGER REFERENCES clientes(id),
    total DECIMAL(10,2) NOT NULL,
    data_pedido DATE DEFAULT CURRENT_DATE
);

INSERT INTO clientes VALUES 
    (1, 'João'), (2, 'Maria'), (3, 'Carlos'), (4, 'Ana');

INSERT INTO pedidos VALUES 
    (1, 1, 100.00, '2024-01-15'),
    (2, 1, 250.00, '2024-02-10'),
    (3, 2, 150.00, '2024-01-20'),
    (5, 5, 50.00, '2024-03-01');  -- cliente_id 5 não existe!

INNER JOIN

-- Apenas registros que existem em ambas as tabelas
SELECT c.nome, p.id AS pedido_id, p.total
FROM clientes c
INNER JOIN pedidos p ON p.cliente_id = c.id;

-- Resultado: João (2x), Maria (1x). Carlos e Ana não aparecem (sem pedidos)
-- Pedido 5 não aparece (cliente_id 5 não existe em clientes)

LEFT JOIN

-- Todos da esquerda + correspondências da direita
SELECT c.nome, p.id AS pedido_id, COALESCE(p.total, 0) AS total
FROM clientes c
LEFT JOIN pedidos p ON p.cliente_id = c.id;

-- Resultado: João (2x), Maria (1x), Carlos (NULL), Ana (NULL)

RIGHT JOIN

-- Todos da direita + correspondências da esquerda
SELECT c.nome, p.id AS pedido_id
FROM clientes c
RIGHT JOIN pedidos p ON p.cliente_id = c.id;

-- Resultado: João (2x), Maria (1x), NULL (pedido 5 sem cliente)

FULL JOIN

-- Todos de ambas as tabelas
SELECT c.nome, p.id AS pedido_id
FROM clientes c
FULL JOIN pedidos p ON p.cliente_id = c.id;

-- Resultado: João, Maria, Carlos, Ana + pedido 5 (sem cliente)

CROSS JOIN

-- Produto cartesiano (cada linha A × cada linha B)
SELECT c.nome, p.id AS pedido_id
FROM clientes c
CROSS JOIN pedidos p;

-- 4 clientes × 4 pedidos = 16 linhas

Self Join

CREATE TABLE funcionarios (
    id SERIAL PRIMARY KEY,
    nome VARCHAR(100),
    gerente_id INTEGER REFERENCES funcionarios(id)
);

INSERT INTO funcionarios VALUES 
    (1, 'Diretor', NULL),
    (2, 'Gerente', 1),
    (3, 'Dev Senior', 2),
    (4, 'Dev Junior', 3);

SELECT f.nome AS funcionario, g.nome AS gerente
FROM funcionarios f
LEFT JOIN funcionarios g ON f.gerente_id = g.id;

Lab: Consulta Relacional

-- Vendas por cliente com total gasto
SELECT 
    c.id,
    c.nome,
    COUNT(p.id) AS total_pedidos,
    COALESCE(SUM(p.total), 0) AS total_gasto,
    COALESCE(AVG(p.total), 0) AS ticket_medio
FROM clientes c
LEFT JOIN pedidos p ON p.cliente_id = c.id
GROUP BY c.id, c.nome
ORDER BY total_gasto DESC;

-- Clientes sem pedidos
SELECT c.nome
FROM clientes c
LEFT JOIN pedidos p ON p.cliente_id = c.id
WHERE p.id IS NULL;

-- Produtos mais vendidos (3 tabelas)
SELECT 
    pr.nome,
    SUM(iv.quantidade) AS total_vendido
FROM produtos pr
JOIN itens_venda iv ON iv.produto_id = pr.id
JOIN vendas v ON v.id = iv.venda_id
WHERE v.data BETWEEN '2024-01-01' AND '2024-12-31'
GROUP BY pr.nome
ORDER BY total_vendido DESC
LIMIT 10;

INNER JOIN = só correspondências. LEFT JOIN = todos da esquerda. Self join = tabela consigo mesma (hierarquias). LEFT JOIN + WHERE NULL = anti-join (registros sem correspondência).