SQL
SQL (Structured Query Language) é a linguagem padrão para interagir com bancos de dados relacionais. Independente do banco que você usa - PostgreSQL, MySQL, SQLite, SQL Server - o SQL core é praticamente o mesmo.
Estrutura de um banco relacional
Seção intitulada “Estrutura de um banco relacional”Dados são organizados em tabelas (como planilhas), com colunas (campos) e linhas (registros). As relações entre tabelas são feitas por chaves.
- Chave primária (PK): identifica cada linha de forma única
- Chave estrangeira (FK): referencia a PK de outra tabela
DDL - Definição de Estrutura
Seção intitulada “DDL - Definição de Estrutura”Criar banco de dados
Seção intitulada “Criar banco de dados”CREATE DATABASE loja;-- Para evitar erro se já existirCREATE DATABASE IF NOT EXISTS loja;Criar tabela
Seção intitulada “Criar tabela”CREATE TABLE usuarios ( id SERIAL PRIMARY KEY, nome VARCHAR(100) NOT NULL, email VARCHAR(150) NOT NULL UNIQUE, nascimento DATE, ativo BOOLEAN DEFAULT TRUE, criado_em TIMESTAMP DEFAULT CURRENT_TIMESTAMP);Tipos comuns:
| Tipo | Descrição |
|---|---|
INT / SERIAL | Inteiro (SERIAL auto-incrementa) |
VARCHAR(n) | Texto com limite de caracteres |
TEXT | Texto sem limite |
DECIMAL(p,s) | Decimal com precisão |
BOOLEAN | Verdadeiro/falso |
DATE | Data (YYYY-MM-DD) |
TIMESTAMP | Data e hora |
-- Tabela com chave estrangeiraCREATE TABLE pedidos ( id SERIAL PRIMARY KEY, usuario_id INT NOT NULL REFERENCES usuarios(id), valor DECIMAL(10, 2) NOT NULL, status VARCHAR(20) DEFAULT 'pendente', criado_em TIMESTAMP DEFAULT CURRENT_TIMESTAMP);Alterar tabela
Seção intitulada “Alterar tabela”ALTER TABLE usuarios ADD COLUMN telefone VARCHAR(20);ALTER TABLE usuarios DROP COLUMN telefone;ALTER TABLE usuarios RENAME COLUMN nome TO nome_completo;Remover tabela
Seção intitulada “Remover tabela”DROP TABLE pedidos;DROP TABLE IF EXISTS pedidos;DML - Manipulação de Dados
Seção intitulada “DML - Manipulação de Dados”-- Inserir um registroINSERT INTO usuarios (nome, email, nascimento)VALUES ('Ana Silva', 'ana@exemplo.com', '1995-03-15');
-- Inserir múltiplos registrosINSERT INTO usuarios (nome, email) VALUES ('Bruno Costa', 'bruno@exemplo.com'), ('Carla Melo', 'carla@exemplo.com'), ('Daniel Rocha', 'daniel@exemplo.com');-- Todos os dadosSELECT * FROM usuarios;
-- Colunas específicasSELECT nome, email FROM usuarios;
-- Com filtroSELECT nome, email FROM usuarios WHERE ativo = TRUE;
-- Múltiplas condiçõesSELECT * FROM usuariosWHERE ativo = TRUE AND nascimento > '1990-01-01';
-- OrdenaçãoSELECT nome, email FROM usuarios ORDER BY nome ASC;SELECT nome, email FROM usuarios ORDER BY criado_em DESC;
-- Limitar resultadosSELECT * FROM usuarios LIMIT 10;SELECT * FROM usuarios LIMIT 10 OFFSET 20; -- paginação (página 3)
-- Busca parcialSELECT * FROM usuarios WHERE nome LIKE '%Silva%';SELECT * FROM usuarios WHERE email LIKE '%@gmail.com';
-- Lista de valoresSELECT * FROM usuarios WHERE id IN (1, 3, 5, 7);
-- IntervaloSELECT * FROM pedidos WHERE valor BETWEEN 100.00 AND 500.00;Funções de agregação
Seção intitulada “Funções de agregação”SELECT COUNT(*) FROM usuarios WHERE ativo = TRUE;SELECT SUM(valor) FROM pedidos;SELECT AVG(valor) FROM pedidos;SELECT MIN(valor), MAX(valor) FROM pedidos;
-- Agrupar e agregarSELECT usuario_id, COUNT(*) AS total_pedidos, SUM(valor) AS total_gastoFROM pedidosGROUP BY usuario_id;
-- Filtrar gruposSELECT usuario_id, COUNT(*) AS total_pedidosFROM pedidosGROUP BY usuario_idHAVING COUNT(*) > 5;-- Sempre use WHERE no UPDATE para não atualizar todos os registrosUPDATE usuariosSET email = 'novo@email.com'WHERE id = 1;
-- Múltiplas colunasUPDATE usuariosSET nome = 'Ana Santos', ativo = FALSEWHERE email = 'ana@exemplo.com';-- Deletar registro específicoDELETE FROM usuarios WHERE id = 5;
-- Deletar com condiçãoDELETE FROM pedidos WHERE status = 'cancelado' AND criado_em < '2024-01-01';
-- Remover todos os dados (mantém a estrutura)TRUNCATE TABLE logs;Diferença entre
DELETEeTRUNCATE:DELETEremove linha por linha (pode terWHERE, é mais lento em tabelas grandes).TRUNCATEremove tudo de uma vez, sem transação individual por linha.
JOINs combinam dados de múltiplas tabelas com base em uma condição de relacionamento.
INNER JOIN
Seção intitulada “INNER JOIN”Retorna apenas os registros que têm correspondência em ambas as tabelas:
SELECT u.nome, p.valor, p.statusFROM pedidos pINNER JOIN usuarios u ON p.usuario_id = u.id;Usuários sem pedidos e pedidos sem usuário válido não aparecem.
LEFT JOIN
Seção intitulada “LEFT JOIN”Retorna todos os registros da tabela à esquerda, e os correspondentes da direita. Onde não há correspondência, as colunas da direita são NULL:
SELECT u.nome, COUNT(p.id) AS total_pedidosFROM usuarios uLEFT JOIN pedidos p ON u.id = p.usuario_idGROUP BY u.id, u.nome;Todos os usuários aparecem, mesmo os que nunca fizeram pedido (total_pedidos = 0 ou NULL).
RIGHT JOIN
Seção intitulada “RIGHT JOIN”O inverso do LEFT JOIN - todos os registros da direita, correspondências ou NULL da esquerda. Menos comum (pode ser reescrito como LEFT JOIN invertendo as tabelas).
FULL OUTER JOIN
Seção intitulada “FULL OUTER JOIN”Retorna todos os registros de ambas as tabelas, com NULL onde não há correspondência:
SELECT u.nome, p.valorFROM usuarios uFULL OUTER JOIN pedidos p ON u.id = p.usuario_id;SELF JOIN
Seção intitulada “SELF JOIN”Join de uma tabela com ela mesma. Útil para dados hierárquicos:
-- Tabela de funcionários com coluna gerente_id referenciando a mesma tabelaSELECT f.nome AS funcionario, g.nome AS gerenteFROM funcionarios fLEFT JOIN funcionarios g ON f.gerente_id = g.id;Subconsultas
Seção intitulada “Subconsultas”-- Usuários que fizeram mais de 3 pedidosSELECT nome FROM usuariosWHERE id IN ( SELECT usuario_id FROM pedidos GROUP BY usuario_id HAVING COUNT(*) > 3);
-- Pedidos com valor acima da médiaSELECT * FROM pedidosWHERE valor > (SELECT AVG(valor) FROM pedidos);Índices
Seção intitulada “Índices”Índices aceleram consultas mas aumentam espaço em disco e levemente o custo de escrita:
-- Criar índice em coluna frequentemente usada em WHERECREATE INDEX idx_usuarios_email ON usuarios(email);
-- Índice compostoCREATE INDEX idx_pedidos_usuario_status ON pedidos(usuario_id, status);
-- Ver índices existentes (PostgreSQL)\d usuariosColunas com PRIMARY KEY e UNIQUE já têm índice automaticamente.
Transações
Seção intitulada “Transações”Transações agrupam operações que devem ser executadas como uma unidade - ou tudo funciona, ou nada:
BEGIN;
UPDATE contas SET saldo = saldo - 500 WHERE id = 1;UPDATE contas SET saldo = saldo + 500 WHERE id = 2;
-- Se chegou aqui sem erro, confirmarCOMMIT;
-- Se algo deu errado, desfazerROLLBACK;Propriedades ACID: Atomicidade, Consistência, Isolamento, Durabilidade.