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