Fundamentos de SQL para desenvolvedores
1. Introdução ao SQL e Modelagem Relacional
SQL (Structured Query Language) é a linguagem padrão para gerenciar e manipular bancos de dados relacionais. Para desenvolvedores, dominar SQL é essencial porque praticamente toda aplicação moderna precisa persistir dados de forma estruturada.
Os conceitos fundamentais incluem:
- Tabelas: estruturas que armazenam dados em formato de linhas e colunas
- Linhas (registros): cada entrada única em uma tabela
- Colunas (campos): atributos que descrevem os dados
- Chave primária: identificador único para cada linha
- Chave estrangeira: referência a uma chave primária de outra tabela
Diferentemente do NoSQL, que prioriza escalabilidade horizontal e esquemas flexíveis, bancos relacionais garantem integridade referencial e consultas complexas através de joins. SQL é declarativo: você diz o que quer, não como obter.
-- Exemplo de modelo relacional simples
-- Tabela usuarios com chave primária
CREATE TABLE usuarios (
id INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(200) UNIQUE NOT NULL
);
-- Tabela pedidos com chave estrangeira
CREATE TABLE pedidos (
id INT PRIMARY KEY,
usuario_id INT NOT NULL,
data_pedido DATE DEFAULT CURRENT_DATE,
valor_total DECIMAL(10,2),
FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
);
2. Comandos DDL e Estrutura de Dados
DDL (Data Definition Language) permite criar e modificar a estrutura do banco.
Comandos principais:
- CREATE TABLE — cria novas tabelas
- ALTER TABLE — modifica tabelas existentes
- DROP TABLE — remove tabelas
Tipos de dados comuns:
- INT, BIGINT — números inteiros
- VARCHAR(n) — strings de tamanho variável
- DATE, TIMESTAMP — datas e horários
- BOOLEAN — valores true/false
- JSON — dados semiestruturados (PostgreSQL, MySQL 8+)
Constraints importantes:
- NOT NULL — campo obrigatório
- UNIQUE — valores não podem se repetir
- DEFAULT — valor padrão
- CHECK — validação personalizada
-- Criando tabela com constraints
CREATE TABLE produtos (
id INT PRIMARY KEY AUTO_INCREMENT,
nome VARCHAR(100) NOT NULL,
preco DECIMAL(10,2) CHECK (preco > 0),
estoque INT DEFAULT 0,
ativo BOOLEAN DEFAULT TRUE,
data_criacao TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Alterando tabela
ALTER TABLE produtos ADD COLUMN categoria VARCHAR(50);
ALTER TABLE produtos MODIFY COLUMN preco DECIMAL(12,2);
ALTER TABLE produtos DROP COLUMN ativo;
3. Comandos DML Essenciais
DML (Data Manipulation Language) lida com os dados dentro das tabelas.
INSERT: insere novos registros
INSERT INTO usuarios (id, nome, email) VALUES (1, 'Maria Silva', 'maria@email.com');
-- Inserção em lote
INSERT INTO produtos (nome, preco) VALUES
('Teclado', 150.00),
('Mouse', 80.00),
('Monitor', 1200.00);
UPDATE e DELETE: sempre use WHERE para evitar alterações em massa
UPDATE produtos SET preco = 140.00 WHERE id = 1;
DELETE FROM produtos WHERE estoque = 0 AND ativo = FALSE;
SELECT básico: a consulta mais comum
SELECT nome, preco FROM produtos WHERE preco > 100 ORDER BY preco DESC;
SELECT * FROM usuarios WHERE email LIKE '%@gmail.com';
4. Consultas Avançadas: Junções, Agrupamentos e Subconsultas
JOINs combinam dados de múltiplas tabelas:
- INNER JOIN — apenas registros correspondentes
- LEFT JOIN — todos da esquerda, mesmo sem correspondência
- RIGHT JOIN — todos da direita
- FULL JOIN — todos de ambas
SELECT u.nome, p.valor_total, p.data_pedido
FROM usuarios u
INNER JOIN pedidos p ON u.id = p.usuario_id
WHERE p.valor_total > 500;
Agregações com GROUP BY:
SELECT u.nome, COUNT(p.id) AS total_pedidos, SUM(p.valor_total) AS gasto_total
FROM usuarios u
LEFT JOIN pedidos p ON u.id = p.usuario_id
GROUP BY u.id, u.nome
HAVING COUNT(p.id) > 3;
Subconsultas:
SELECT nome, preco
FROM produtos
WHERE preco > (SELECT AVG(preco) FROM produtos);
-- Subconsulta correlacionada
SELECT u.nome,
(SELECT COUNT(*) FROM pedidos p WHERE p.usuario_id = u.id) AS qtd_pedidos
FROM usuarios u;
5. Indexação e Otimização de Consultas
Índices aceleram buscas, mas têm custo em escrita. Tipos comuns:
- B-tree: padrão, eficiente para igualdade e intervalos
- Hash: apenas igualdade, muito rápido
- Composto: múltiplas colunas, ordem importa
Boas práticas:
- Evite SELECT * — busque apenas colunas necessárias
- Use EXPLAIN para analisar planos de execução
- Índices em colunas usadas em WHERE, JOIN e ORDER BY
- Normalização até 3ª forma normal, mas sem exageros
-- Criando índices
CREATE INDEX idx_produtos_categoria ON produtos(categoria);
CREATE INDEX idx_pedidos_data ON pedidos(data_pedido);
-- Analisando consulta
EXPLAIN SELECT * FROM pedidos WHERE data_pedido > '2024-01-01';
6. Transações, Controle de Concorrência e Segurança
ACID garante confiabilidade:
- Atomicidade: tudo ou nada
- Consistência: dados válidos após transação
- Isolamento: transações concorrentes não interferem
- Durabilidade: dados persistidos após commit
BEGIN TRANSACTION;
UPDATE contas SET saldo = saldo - 100 WHERE id = 1;
UPDATE contas SET saldo = saldo + 100 WHERE id = 2;
COMMIT;
-- ROLLBACK em caso de erro
Níveis de isolamento (do menor ao maior isolamento):
1. READ UNCOMMITTED — sujo, leituras não confirmadas
2. READ COMMITTED — apenas dados confirmados
3. REPEATABLE READ — leitura consistente durante transação
4. SERIALIZABLE — execução sequencial
Prevenção de SQL Injection — sempre use prepared statements:
-- Inseguro (NUNCA faça isso)
SELECT * FROM usuarios WHERE email = '$email';
-- Seguro com parâmetros
SELECT * FROM usuarios WHERE email = ?;
-- A biblioteca substitui ? pelo valor sanitizado
7. Funções, Views e Stored Procedures
Funções nativas são essenciais no dia a dia:
-- Funções de string
SELECT UPPER(nome), LENGTH(email), CONCAT(nome, ' <', email, '>') FROM usuarios;
-- Funções de data
SELECT nome, DATEDIFF(CURRENT_DATE, data_cadastro) AS dias_desde_cadastro
FROM usuarios;
-- Funções matemáticas
SELECT ROUND(AVG(preco), 2) FROM produtos;
Views simplificam consultas complexas:
CREATE VIEW vw_clientes_fieis AS
SELECT u.nome, COUNT(p.id) AS total_pedidos, SUM(p.valor_total) AS total_gasto
FROM usuarios u
JOIN pedidos p ON u.id = p.usuario_id
GROUP BY u.id, u.nome
HAVING COUNT(p.id) >= 5;
-- Usando a view como se fosse tabela
SELECT * FROM vw_clientes_fieis ORDER BY total_gasto DESC;
Stored Procedures para automação:
DELIMITER //
CREATE PROCEDURE sp_aplica_desconto(IN percentual DECIMAL(5,2))
BEGIN
UPDATE produtos
SET preco = preco * (1 - percentual/100)
WHERE estoque > 100 AND ativo = TRUE;
END //
DELIMITER ;
CALL sp_aplica_desconto(10.0);
Triggers executam automaticamente em eventos:
CREATE TRIGGER trg_atualiza_estoque
AFTER INSERT ON itens_pedido
FOR EACH ROW
BEGIN
UPDATE produtos
SET estoque = estoque - NEW.quantidade
WHERE id = NEW.produto_id;
END;
SQL é uma habilidade fundamental para qualquer desenvolvedor. Dominar desde consultas básicas até otimização e segurança diferencia profissionais. Pratique com projetos reais, estude planos de execução e mantenha-se atualizado com as evoluções dos bancos de dados relacionais modernos.
Referências
- Documentação Oficial do PostgreSQL — Tutorial completo de SQL com exemplos práticos no banco PostgreSQL
- W3Schools SQL Tutorial — Guia interativo para iniciantes com exercícios e exemplos executáveis
- MySQL Documentation: SQL Statements — Referência completa de comandos SQL para MySQL 8.0
- Use The Index, Luke! — Guia avançado sobre indexação e otimização de consultas SQL
- SQL Injection Prevention Cheat Sheet (OWASP) — Melhores práticas de segurança para evitar injeção SQL
- SQLBolt - Learn SQL with Interactive Exercises — Tutorial interativo gratuito com exercícios práticos progressivos
- Mode Analytics SQL Tutorial — Curso avançado focado em análise de dados com SQL e funções de janela