Ao terminar esta aula, você vai conseguir
- Separar entidades e relações em tabelas coerentes
- Aplicar primary key, foreign key, unique e check
- Reproduzir e interpretar uma violação de integridade
Modelagem relacional transforma regras do negócio em tabelas e relações. Nesta aula, você vai representar alunos, cursos e matrículas e fazer o PostgreSQL rejeitar estados impossíveis. O resultado não será apenas um diagrama: serão restrições executáveis e um erro de integridade que você sabe interpretar.
Pense num evento com credenciais. Cada pessoa recebe um número único; a lista de inscrições só pode citar pessoas e oficinas cadastradas; a mesma pessoa não pode ocupar duas vezes a mesma vaga. Primary key, foreign key e unique formalizam regras parecidas. O limite da analogia é que o banco não descobre as regras do evento sozinho. Você precisa expressá-las, e mudanças exigem migração.
Separe entidades sem perder a relação
Alunos e cursos existem por conta própria. Matrícula representa a relação entre os dois. Um modelo inicial é:
CREATE TABLE alunos (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
nome text NOT NULL,
email text NOT NULL UNIQUE,
ativo boolean NOT NULL DEFAULT true
);
CREATE TABLE cursos (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
titulo text NOT NULL,
carga_horas integer NOT NULL CHECK (carga_horas > 0)
);A chave primária identifica uma linha. UNIQUE impede e-mails repetidos. O
CHECK exige carga positiva. NOT NULL trata ausência; ele não impede texto
vazio. Se '' também for inválido, a aplicação e uma restrição adicional devem
representar essa decisão.
Agora crie a tabela de ligação:
CREATE TABLE matriculas (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
aluno_id bigint NOT NULL REFERENCES alunos(id),
curso_id bigint NOT NULL REFERENCES cursos(id),
status text NOT NULL CHECK (status IN ('ativa', 'concluida', 'cancelada')),
matriculado_em timestamptz NOT NULL DEFAULT now(),
UNIQUE (aluno_id, curso_id)
);A chave estrangeira garante que aluno e curso existam. A restrição única composta impede repetir o mesmo par, mas permite que um aluno participe de cursos diferentes e que um curso tenha vários alunos.
Evite guardar na matrícula o nome atual do aluno só para poupar o primeiro join. Essa cópia pode divergir quando o cadastro muda. Dados derivados podem ser úteis em relatórios ou fotografias históricas, mas precisam de uma regra clara de atualização. Comece com uma fonte por fato e introduza duplicação apenas depois de medir a necessidade.
Decida o que acontece na remoção
Sem uma ação explícita, o PostgreSQL normalmente bloqueia a remoção de uma linha
que ainda é referenciada. Isso protege o histórico. ON DELETE CASCADE removeria
as linhas dependentes; SET NULL preservaria a linha e limparia a referência,
desde que a coluna aceite NULL.
Não escolha CASCADE para eliminar uma mensagem incômoda. Pergunte: uma
matrícula deve desaparecer quando o curso é removido, ou o curso deveria ser
arquivado? Dados históricos geralmente pedem preservação. A ação correta vem do
ciclo de vida do negócio.
Reproduza uma violação útil
Com apenas um aluno de ID 1, tente:
INSERT INTO matriculas (aluno_id, curso_id, status)
VALUES (999, 10, 'ativa');O servidor rejeita a linha porque alunos.id = 999 não existe. Não “resolva”
desativando a foreign key. Verifique o identificador recebido e devolva uma
mensagem coerente. Outro erro controlado é repetir o mesmo par de aluno e curso;
a restrição única deve impedir a duplicata.
O laboratório usa tabelas representadas por JSON e um interpretador de SQL
básico no navegador. Ele não aplica chaves, restrições ou joins e não se conecta
ao PostgreSQL. Consulte alunos e depois troque para SELECT * FROM matriculas WHERE curso_id = 101;. Espere duas linhas. Esse exercício serve para conhecer
os dados; as garantias desta aula precisam ser praticadas num banco isolado.
Sua missão é escrever o modelo, inserir um caso válido e reproduzir duas violações: chave estrangeira ausente e matrícula duplicada. Registre qual regra barrou cada comando. Na próxima aula, vamos operar essas tabelas com CRUD e confirmar cada mudança com saídas observáveis.
Laboratório ao vivo
Inspecione tabelas relacionadas
Consulte alunos ativos e depois matrículas de um curso. O simulador executa SELECT básico em uma tabela por vez; não oferece joins nem PostgreSQL real.
Resultado
Pare e pense
Qual é a função de uma chave estrangeira?
A foreign key mantém integridade referencial: o valor precisa existir na chave alvo, salvo quando NULL é permitido.
Faça sem copiar
Modele alunos, cursos e matrículas. Impeça e-mail duplicado, carga negativa e duas matrículas do mesmo aluno no mesmo curso.
Fontes para consultar
Terminou a missão?
Marque apenas quando você conseguir explicar o conceito e concluir o desafio. O progresso fica salvo somente neste navegador.
Próxima: CRUD no PostgreSQL com SQL e RETURNING →