Prática - Consultas Básicas Abrangentes

Prática: Consultas Básicas Abrangentes

Nas primeiras 5 lições, aprendemos o "ouvir, falar, ler e escrever" do SQL — criar tabelas, consultar, filtrar, ordenar, operações CRUD e tipos de dados. Agora é hora de combinar essas habilidades para resolver problemas reais de negócio. Esta lição não tem sintaxe nova — apenas prática.


Requisitos do Projeto

Você é um analista de dados em uma empresa de e-commerce e precisa extrair as seguintes informações do banco de dados da empresa:

  1. Gestão de Funcionários: Consultar funcionários em departamentos específicos, ordenar por salário, paginar resultados
  2. Filtragem de Produtos: Filtrar produtos por faixa de preço e estoque, busca fuzzy por nomes de produtos
  3. Análise de Pedidos: Consultar pedidos recentes, calcular valores de pedidos, atualizar status de pedidos
  4. Manutenção de Dados: Atualização em lote de preços, limpeza de dados expirados, inserção de novos dados

O banco de dados contém quatro tabelas: employees, departments, orders, products.


Implementação Completa do Código

Passo 1: Criar Banco de Dados e Tabelas

SQL
-- Criar tabela departments
CREATE TABLE departments (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    location TEXT
);

-- Criar tabela employees
CREATE TABLE employees (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    department_id INTEGER,
    salary DECIMAL(10,2),
    hire_date DATE,
    FOREIGN KEY (department_id) REFERENCES departments(id)
);

-- Criar tabela products
CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    category TEXT,
    price DECIMAL(10,2),
    stock INTEGER DEFAULT 0
);

-- Criar tabela orders
CREATE TABLE orders (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    customer_name TEXT NOT NULL,
    product_id INTEGER,
    quantity INTEGER,
    order_date DATE,
    FOREIGN KEY (product_id) REFERENCES products(id)
);

Passo 2: Inserir Dados de Teste

SQL
-- Inserir dados dos departamentos
INSERT INTO departments (name, location) VALUES
    ('Engineering', 'New York'),
    ('Marketing', 'Los Angeles'),
    ('Finance', 'New York'),
    ('HR', 'Chicago');

-- Inserir dados dos funcionários
INSERT INTO employees (name, department_id, salary, hire_date) VALUES
    ('John', 1, 15000.00, '2023-01-15'),
    ('Jane', 1, 18000.00, '2022-06-01'),
    ('Bob', 2, 12000.00, '2023-03-20'),
    ('Alice', 3, 13000.00, '2021-11-10'),
    ('Charlie', 1, 20000.00, '2020-08-05'),
    ('Diana', 2, 11000.00, '2024-01-10'),
    ('Eve', NULL, 9000.00, '2024-05-01'),
    ('Frank', 3, 14000.00, '2022-09-15');

-- Inserir dados dos produtos
INSERT INTO products (name, category, price, stock) VALUES
    ('iPhone 15', 'Phone', 5999.00, 100),
    ('MacBook Pro', 'Computer', 12999.00, 50),
    ('AirPods Pro', 'Accessory', 1899.00, 200),
    ('iPad Air', 'Tablet', 4799.00, 80),
    ('Apple Watch', 'Watch', 2999.00, 150),
    ('Magic Keyboard', 'Accessory', 999.00, 300),
    ('Mac Mini', 'Computer', 4499.00, 0),
    ('iPhone 14', 'Phone', 4999.00, 20);

-- Inserir dados dos pedidos
INSERT INTO orders (customer_name, product_id, quantity, order_date) VALUES
    ('Tom', 1, 1, '2024-06-01'),
    ('Lucy', 3, 2, '2024-06-02'),
    ('Mike', 2, 1, '2024-06-03'),
    ('Tom', 5, 1, '2024-06-05'),
    ('Sarah', 4, 3, '2024-06-10'),
    ('Lucy', 6, 5, '2024-06-15'),
    ('David', 1, 2, '2024-06-20'),
    ('Mike', 8, 1, '2024-06-25');

Passo 3: Consultas de Gestão de Funcionários

SQL
-- Q1: Consultar todos os funcionários de Engenharia, ordenados por salário do maior para o menor
SELECT name, salary, hire_date
FROM employees
WHERE department_id = 1
ORDER BY salary DESC;

Saída:

TEXT
name     salary    hire_date
-------  --------  ----------
Charlie  20000.00  2020-08-05
Jane     18000.00  2022-06-01
John     15000.00  2023-01-15
SQL
-- Q2: Consultar os 3 funcionários com maior salário (paginação: página 1, 3 por página)
SELECT name, salary, department_id
FROM employees
ORDER BY salary DESC
LIMIT 3 OFFSET 0;

Saída:

TEXT
name     salary    department_id
-------  --------  -------------
Charlie  20000.00  1
Jane     18000.00  1
John     15000.00  1
SQL
-- Q3: Consultar página 2 (3 registros por página)
SELECT name, salary, department_id
FROM employees
ORDER BY salary DESC
LIMIT 3 OFFSET 3;

Saída:

TEXT
name   salary    department_id
-----  --------  -------------
Frank  14000.00  3
Alice  13000.00  3
Bob    12000.00  2
SQL
-- Q4: Consultar funcionários sem departamento atribuído
SELECT name, salary
FROM employees
WHERE department_id IS NULL;

Saída:

TEXT
name  salary
----  --------
Eve   9000.00

Passo 4: Consultas de Filtragem de Produtos

SQL
-- Q5: Consultar produtos com preço entre 1000 e 5000, ordenados por preço ascendente
SELECT name, category, price, stock
FROM products
WHERE price BETWEEN 1000 AND 5000
ORDER BY price ASC;

Saída:

TEXT
name            category  price    stock
--------------  --------  -------  -----
AirPods Pro     Accessory 1899.00  200
Apple Watch     Watch     2999.00  150
Mac Mini        Computer  4499.00  0
iPad Air        Tablet    4799.00  80
SQL
-- Q6: Busca fuzzy por produtos com "iPhone" no nome
SELECT name, price, stock
FROM products
WHERE name LIKE '%iPhone%';

Saída:

TEXT
name        price    stock
----------  -------  -----
iPhone 15   5999.00  100
iPhone 14   4999.00  20
SQL
-- Q7: Consultar produtos em estoque (stock > 0) com preço abaixo de 3000
SELECT name, price, stock
FROM products
WHERE stock > 0 AND price < 3000
ORDER BY price DESC;

Saída:

TEXT
name            price    stock
--------------  -------  -----
AirPods Pro     1899.00  200
Magic Keyboard  999.00   300

Passo 5: Consultas de Análise de Pedidos

SQL
-- Q8: Consultar os 5 pedidos mais recentes, mostrando nome do produto e nome do cliente
SELECT o.customer_name, p.name AS product_name,
       o.quantity, o.order_date
FROM orders o
JOIN products p ON o.product_id = p.id
ORDER BY o.order_date DESC
LIMIT 5;

Saída:

TEXT
customer_name  product_name   quantity  order_date
-------------  -------------  --------  ----------
Mike           iPhone 14      1         2024-06-25
David          iPhone 15      2         2024-06-20
Lucy           Magic Keyboard 5         2024-06-15
Sarah          iPad Air       3         2024-06-10
Tom            Apple Watch    1         2024-06-05
SQL
-- Q9: Consultar o valor de cada pedido (preço unitário × quantidade), ordenado por valor descendente
SELECT o.customer_name, p.name AS product_name,
       p.price, o.quantity,
       (p.price * o.quantity) AS total_amount
FROM orders o
JOIN products p ON o.product_id = p.id
ORDER BY total_amount DESC;

Saída:

TEXT
customer_name  product_name   price     quantity  total_amount
-------------  -------------  --------  --------  ------------
Sarah          iPad Air       4799.00   3         14397.00
Mike           MacBook Pro    12999.00  1         12999.00
David          iPhone 15      5999.00   2         11998.00
Tom            iPhone 15      5999.00   1         5999.00
Lucy           Magic Keyboard 999.00    5         4995.00
Mike           iPhone 14      4999.00   1         4999.00
Tom            Apple Watch    2999.00   1         2999.00
Lucy           AirPods Pro    1899.00   2         3798.00

Passo 6: Operações de Manutenção de Dados

SQL
-- Q10: Aumentar o preço de todos os produtos da categoria "Accessory" em 10%
-- Primeiro confirmar o escopo afetado
SELECT name, price FROM products WHERE category = 'Accessory';

Antes do ajuste:

TEXT
name            price
--------------  -------
AirPods Pro     1899.00
Magic Keyboard  999.00
SQL
-- Executar a atualização
UPDATE products
SET price = ROUND(price * 1.1, 2)
WHERE category = 'Accessory';

-- Verificar resultados
SELECT name, price FROM products WHERE category = 'Accessory';

Após o ajuste:

TEXT
name            price
--------------  -------
AirPods Pro     2088.90
Magic Keyboard  1098.90
SQL
-- Q11: Marcar produtos sem estoque (stock = 0) como descontinuados
-- Aqui deletamos produtos sem estoque como exemplo
-- Primeiro confirmar
SELECT id, name, stock FROM products WHERE stock = 0;

Resultado da confirmação:

TEXT
id  name      stock
--  --------  -----
7   Mac Mini  0
SQL
-- Deletar produtos sem estoque
DELETE FROM products WHERE stock = 0;

-- Q12: Inserir um novo produto
INSERT INTO products (name, category, price, stock)
VALUES ('AirTag', 'Accessory', 229.00, 500);

-- Visualização final de todos os produtos
SELECT id, name, category, price, stock
FROM products
ORDER BY id;

Lista final de produtos:

TEXT
id  name            category  price     stock
--  --------------  --------  --------  -----
1   iPhone 15       Phone     5999.00   100
2   MacBook Pro     Computer  12999.00  50
3   AirPods Pro     Accessory 2088.90   200
4   iPad Air        Tablet    4799.00   80
5   Apple Watch     Watch     2999.00   150
6   Magic Keyboard  Accessory 1098.90   300
8   iPhone 14       Phone     4999.00   20
9   AirTag          Accessory 229.00    500

Análise do Código

Consulta Pontos de Conhecimento Utilizados Técnicas-Chave
Q1-Q3 SELECT + WHERE + ORDER BY + LIMIT/OFFSET Paginação usa LIMIT n OFFSET (página-1)*n
Q4 WHERE + IS NULL Deve usar IS NULL para verificar NULL
Q5 BETWEEN + ORDER BY BETWEEN inclui ambos os valores dos extremos
Q6 LIKE + curinga % %palavra-chave% corresponde em qualquer posição
Q7 Múltiplas condições AND + operadores de comparação Combinando condições para filtragem
Q8 JOIN + ORDER BY + LIMIT Consultas relacionando múltiplas tabelas
Q9 JOIN + cálculo de expressão + ORDER BY Cálculos em SELECT
Q10 UPDATE + WHERE + ROUND SELECT para confirmar antes de atualizar
Q11 DELETE + WHERE SELECT para confirmar antes de deletar
Q12 INSERT + verificação final Consulta para verificar após inserção

❓ Perguntas Frequentes

P: Com paginação LIMIT OFFSET, se dados forem adicionados ou deletados, haverá duplicatas ou registros faltando? R: Sim. Se os dados mudarem durante a paginação, a paginação baseada em OFFSET pode resultar em registros duplicados ou faltando. Uma abordagem mais estável é "paginação por cursor": WHERE id > último_id_da_página_anterior LIMIT 10, mas isso requer que cada registro tenha uma chave de ordenação consistente.

P: LIKE '%palavra-chave%' causa falha de índice. E para grandes conjuntos de dados? R: LIKE começando com curinga realmente não pode usar um índice regular. Para grandes conjuntos de dados, considere: ① Usar busca de texto completo (FTS5, suportado pelo SQLite); ② Usar mecanismos de busca como Elasticsearch na camada de aplicação; ③ Se apenas correspondência de prefixo é necessária, LIKE 'palavra-chave%' pode utilizar um índice.

P: E se duas tabelas tiverem o mesmo nome de coluna em uma consulta JOIN? R: Use aliases de tabela ou aliases de coluna para diferenciar. Por exemplo: SELECT e.name, d.name AS dept_name FROM employees e JOIN departments d ON e.department_id = d.id;. É um bom hábito usar aliases de coluna para uma saída mais clara.

P: Operações UPDATE e DELETE podem ser desfeitas? R: Se dentro de uma transação (entre BEGIN...COMMIT), você pode usar ROLLBACK para desfazer. Se já fez COMMIT, no SQLite é basicamente irrecuperável (a menos que você tenha um backup). MySQL pode recuperar através de replay de binlog. Então sempre faça backup antes de operações em produção.


📖 Resumo


📝 Exercícios

Exercício 1 (⭐)

Escreva consultas para completar as seguintes tarefas:

  1. Consultar todos os funcionários que entraram em 2023, ordenados por data de contratação ascendente
  2. Consultar o produto mais caro da categoria "Phone"
  3. Consultar todos os pedidos do cliente "Tom", mostrando nome do produto e quantidade

Exercício 2 (⭐⭐)

Escreva consultas para completar as seguintes tarefas:

  1. Consultar o número de funcionários em cada departamento (dica: requer GROUP BY — você pode pular para lições posteriores e voltar para desafiar isso)
  2. Consultar o valor total de todos os pedidos
  3. Diminuir o preço de produtos da categoria "Computer" em 5%, depois consultar para verificar

Exercício 3 (⭐⭐⭐)

Simule um cenário de "alerta de estoque baixo":

  1. Consultar todos os produtos com estoque abaixo de 50, ordenados por estoque ascendente
  2. Inserir esses produtos em uma nova tabela low_stock_alert
  3. Aumentar o estoque de cada um desses produtos em 100
  4. Verificar os resultados da atualização

Próxima Lição

👉 07-join-intro - Introdução a Consultas JOIN

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%