Integridade de entidade, referencial e regras de negócio

Integridade transforma regras em garantias do banco
Na aula anterior, definimos chaves para identificar tuplas e conectar relações. Uma identificação bem escolhida, porém, só protege os dados quando o esquema rejeita estados incompatíveis: identidade ausente, referência sem destino, percentual fora da faixa ou publicação sem data.
Integridade de dados é a preservação dessas condições durante inserções, alterações e exclusões. No modelo relacional, restrições declarativas fazem o SGBD verificar as regras independentemente de qual tela, script, integração ou pessoa enviou o comando.
Validar também na aplicação melhora a experiência do usuário, mas não substitui a garantia central. Outro cliente, uma importação ou duas operações concorrentes podem contornar uma validação presente apenas numa interface.
Quatro perguntas organizam as regras
Para cada atributo ou relação, pergunte:
- o valor pertence ao domínio esperado?
- a tupla possui identidade obrigatória e não repetida?
- toda referência exigida encontra um destino válido?
- as combinações de valores respeitam as regras do negócio?
Essas perguntas correspondem, respectivamente, à integridade de domínio, de entidade, referencial e às demais restrições semânticas. As categorias se complementam; não são alternativas.
Integridade de domínio limita valores admissíveis
O domínio de um atributo reúne os valores que fazem sentido naquele papel. Na implementação, combinamos tipos, nulabilidade e restrições para aproximar esse conjunto.
CREATE TABLE matricula (
id_estudante bigint NOT NULL,
id_trilha bigint NOT NULL,
progresso smallint NOT NULL,
situacao text NOT NULL,
CONSTRAINT matricula_progresso_valido
CHECK (progresso BETWEEN 0 AND 100),
CONSTRAINT matricula_situacao_valida
CHECK (situacao IN ('ativa', 'concluida', 'cancelada'))
);
O tipo smallint impede textos, mas ainda aceita números negativos e maiores que 100. CHECK restringe a faixa. O tipo textual aceita inúmeras sequências; outro CHECK limita os estados reconhecidos. NOT NULL declara que ausência não é uma situação válida.
CHECK e NOT NULL resolvem problemas diferentes
Em PostgreSQL, um CHECK é considerado satisfeito quando sua expressão resulta em verdadeiro ou desconhecido. Como comparações com NULL frequentemente produzem desconhecido, isto não impede ausência:
progresso smallint CHECK (progresso BETWEEN 0 AND 100)
Para exigir o valor e validar sua faixa, precisamos das duas regras:
progresso smallint NOT NULL
CHECK (progresso BETWEEN 0 AND 100)
Integridade de entidade preserva a identidade
A integridade de entidade exige que cada tupla possua uma identidade inequívoca. Uma PRIMARY KEY reúne duas garantias: seus valores são únicos e não podem ser nulos.
CREATE TABLE trilha (
id_trilha bigint PRIMARY KEY,
slug text NOT NULL UNIQUE,
titulo text NOT NULL
);
id_trilha protege a identidade primária. slug permanece uma chave candidata de negócio, portanto recebe UNIQUE e NOT NULL. Criar um identificador substituto não torna aceitáveis duas trilhas com o mesmo slug.
Restrições únicas com valores nulos exigem cuidado. O tratamento de NULL em UNIQUE possui diferenças entre produtos; no PostgreSQL, por padrão, dois valores nulos são considerados distintos para essa verificação. Se a regra é “exatamente um valor e nunca ausente”, declare também NOT NULL em vez de depender de uma suposição portátil.
Integridade referencial impede registros órfãos
Uma FOREIGN KEY exige que cada referência não nula corresponda a uma chave primária ou única da relação referenciada. Assim, um módulo não pode apontar para uma trilha inexistente:
CREATE TABLE modulo (
id_modulo bigint PRIMARY KEY,
id_trilha bigint NOT NULL,
titulo text NOT NULL,
ordem integer NOT NULL CHECK (ordem > 0),
CONSTRAINT modulo_trilha_fk
FOREIGN KEY (id_trilha)
REFERENCES trilha (id_trilha),
CONSTRAINT modulo_ordem_unica
UNIQUE (id_trilha, ordem)
);
Observe como as regras cooperam:
- a PK identifica o módulo;
NOT NULLtorna a participação na trilha obrigatória;- a FK garante que a trilha exista;
CHECKimpede ordem não positiva;UNIQUEimpede dois módulos na mesma posição da mesma trilha.
A FK sozinha permite NULL quando a coluna é anulável. Isso pode representar uma relação opcional, mas não uma participação obrigatória. A intenção precisa aparecer na combinação das restrições.
Referências compostas e valores parcialmente ausentes
Em uma FK composta, o comportamento padrão de muitos SGBDs permite dispensar a correspondência quando algum componente é nulo. No PostgreSQL, MATCH FULL exige que todas as partes sejam nulas ou que nenhuma seja; uma mistura falha.
FOREIGN KEY (codigo_curso, numero_edicao)
REFERENCES edicao (codigo_curso, numero_edicao)
MATCH FULL
Se a relação é obrigatória, NOT NULL em cada componente é ainda mais direto. Como detalhes de nulidade composta variam entre produtos, confirme a documentação do SGBD adotado.
Alterar ou excluir o pai exige uma política
A integridade referencial não termina na inserção. Se uma trilha já possui módulos, o que deve ocorrer quando alguém tenta excluí-la? SQL oferece ações para ON DELETE e ON UPDATE, mas nenhuma delas é universalmente correta.
| Ação | Efeito geral | Quando pode representar o domínio |
|---|---|---|
NO ACTION | a operação falha se a violação ainda existir no momento da verificação | estado pode ser corrigido antes de uma verificação adiada |
RESTRICT | bloqueia a alteração que encontra referências | pai e filho possuem ciclos de vida independentes |
CASCADE | propaga exclusão ou atualização aos dependentes | o filho é componente e não existe sem o pai |
SET NULL | mantém o filho e remove a referência | associação é opcional e ausência tem significado |
SET DEFAULT | troca a referência por um valor padrão | existe um destino padrão válido e semanticamente correto |
Um exemplo com decisões diferentes
Um módulo é componente de uma trilha e pode não fazer sentido isoladamente. Se a política realmente remove trilhas, ON DELETE CASCADE pode representar essa dependência:
FOREIGN KEY (id_trilha)
REFERENCES trilha (id_trilha)
ON DELETE CASCADE
Uma matrícula, porém, pode ter valor histórico e envolver um estudante independente da trilha. Apagá-la silenciosamente junto com a trilha talvez seja incorreto. RESTRICT, arquivamento lógico ou uma política explícita de retenção podem preservar melhor o significado.
NO ACTION não é apenas outro nome para RESTRICT
No PostgreSQL, NO ACTION é o padrão. Quando a restrição é adiável, a violação pode ser corrigida antes do momento de verificação. RESTRICT impede a ação imediatamente e não admite esse adiamento. Em fluxos comuns, ambos podem terminar com uma mensagem de erro, mas o momento e as possibilidades dentro da transação diferem.
Restrições imediatas e adiáveis
Normalmente, restrições são verificadas após cada comando. Algumas regras UNIQUE, PRIMARY KEY, EXCLUDE e FOREIGN KEY podem ser declaradas DEFERRABLE no PostgreSQL e verificadas ao final da transação.
Isso ajuda em operações que passam por um estado intermediário inválido, mas terminam válidas — por exemplo, trocar posições únicas de dois módulos. Não significa aceitar inconsistência depois do COMMIT.
CONSTRAINT modulo_ordem_unica
UNIQUE (id_trilha, ordem)
DEFERRABLE INITIALLY IMMEDIATE
O uso deve ser consciente e será retomado na aula de transações. NOT NULL e CHECK não são adiáveis no PostgreSQL.
Regras de negócio podem envolver uma linha inteira
Uma restrição CHECK de tabela pode comparar colunas da própria tupla. Uma trilha publicada precisa ter data de publicação; um rascunho ainda não:
CREATE TABLE trilha (
id_trilha bigint PRIMARY KEY,
situacao text NOT NULL,
publicada_em timestamptz,
CONSTRAINT trilha_situacao_valida
CHECK (situacao IN ('rascunho', 'publicada', 'arquivada')),
CONSTRAINT trilha_publicacao_coerente
CHECK (
(situacao = 'rascunho' AND publicada_em IS NULL)
OR
(situacao IN ('publicada', 'arquivada') AND publicada_em IS NOT NULL)
)
);
Nomear a restrição torna o erro mais compreensível e facilita futuras alterações. O nome deve comunicar a regra, não repetir apenas o tipo técnico.
Nem toda regra cabe em CHECK
No PostgreSQL, CHECK deve depender da linha inserida ou alterada. Consultar outras linhas ou tabelas dentro da expressão pode parecer funcionar em um teste simples, mas não garante consistência após mudanças posteriores e pode comprometer restaurações.
Escolha o mecanismo pela abrangência:
- um valor: tipo,
NOT NULL, domínio ouCHECK; - colunas da mesma linha:
CHECKde tabela; - unicidade entre linhas:
UNIQUEou, em casos específicos do produto, exclusão/índice apropriado; - existência em outra relação:
FOREIGN KEY; - regra agregada, temporal ou de transição: possivelmente trigger, procedimento ou serviço transacional, com testes de concorrência;
- fato externo ao banco: aplicação ou integração, sem retirar do banco as invariáveis que ele ainda consegue declarar.
Adicionar uma restrição também exige cuidar dos dados existentes
Uma tabela antiga pode conter valores que a nova regra rejeitaria. Antes da migração:
- consulte e quantifique as violações;
- defina como corrigir, completar, consolidar ou separar os registros;
- aplique a restrição com estratégia compatível com volume e disponibilidade;
- valide todo o conjunto, não apenas inserções futuras;
- monitore erros para localizar clientes que ainda enviam dados incompatíveis.
No PostgreSQL, adicionar uma restrição normalmente verifica os dados existentes. Há estratégias como criar certas restrições como NOT VALID e validá-las depois, mas esse recurso é específico do produto e não deve virar pretexto para manter dados inválidos indefinidamente.
Erros comuns
- validar somente na interface: outros caminhos de escrita continuam desprotegidos;
- usar DEFAULT como regra: o padrão preenche omissão, mas não rejeita alternativas inválidas;
- esquecer NOT NULL junto de CHECK: resultado desconhecido pode passar pela verificação;
- criar ID substituto e abandonar UNIQUE do negócio: fatos duplicados continuam possíveis;
- declarar FK anulável para uma relação obrigatória: a ausência contorna a correspondência;
- aplicar CASCADE por conveniência: o alcance real pode apagar fatos independentes;
- usar SET NULL numa coluna NOT NULL: a própria ação produzirá outra violação;
- confundir NO ACTION com RESTRICT: restrições adiáveis tornam a diferença relevante;
- consultar outras linhas em CHECK: o mecanismo não acompanha corretamente mudanças externas à linha;
- esconder toda regra em trigger: a intenção fica menos visível quando uma restrição declarativa bastaria;
- adicionar restrição sem auditar o legado: a migração falha ou a inconsistência permanece adiada.
Roteiro de revisão
Para cada tabela, revise:
- quais atributos são obrigatórios e por quê;
- quais valores e combinações pertencem ao domínio;
- qual chave preserva a identidade e quais candidatas também são únicas;
- quais participações são obrigatórias ou opcionais;
- o que acontece ao atualizar ou excluir cada chave referenciada;
- quais filhos são componentes e quais possuem vida própria;
- se a regra envolve uma coluna, uma linha, várias linhas ou outro sistema;
- se a mensagem e o nome da restrição ajudam a diagnosticar a violação;
- como dados existentes serão validados durante a migração;
- quais cenários concorrentes precisam de teste.
O que você deve guardar
Integridade de domínio limita valores; integridade de entidade garante identidade não nula e não repetida; integridade referencial exige destinos válidos; regras de negócio preservam combinações semanticamente coerentes.
NOT NULL, CHECK, UNIQUE, PRIMARY KEY e FOREIGN KEY são garantias complementares. Ações referenciais expressam ciclos de vida: bloquear, propagar, remover a associação ou redirecioná-la. Regras simples devem permanecer declarativas; mecanismos procedurais ficam para invariáveis que realmente ultrapassam a capacidade das restrições.
Na próxima aula, aplicaremos essas garantias ao transformar entidades, atributos, relacionamentos e cardinalidades do modelo ER em um esquema relacional completo.
Referências
- PostgreSQL Global Development Group — Constraints. Acesso em 29 ago. 2026.
- PostgreSQL Global Development Group — CREATE TABLE. Acesso em 29 ago. 2026.
- PostgreSQL Global Development Group — Modifying Tables. Acesso em 29 ago. 2026.
- Oracle — Database Concepts: Data Integrity. Acesso em 29 ago. 2026.
- Oracle — Maintaining Data Integrity in Database Applications. Acesso em 29 ago. 2026.
