Pesquisar conteúdos

Encontre uma trilha ou aula pelo assunto.

Experimente pesquisar por “governança”, “ITIL” ou “planejamento”.

Conteúdo da trilha

Integridade de entidade, referencial e regras de negócio

Veja como restrições preservam identidades, referências válidas e condições que os dados precisam respeitar.
Registros passam por validações de domínio, coerência e referência; duplicidade e referência sem destino são bloqueadas

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:

  1. o valor pertence ao domínio esperado?
  2. a tupla possui identidade obrigatória e não repetida?
  3. toda referência exigida encontra um destino válido?
  4. 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.

Um registro passa por regras de domínio, identidade e referência antes de integrar um estado válido
Tipos, nulabilidade, CHECK, chaves e referências protegem aspectos diferentes. Um registro só é consistente quando satisfaz todas as regras aplicáveis.

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 NULL torna a participação na trilha obrigatória;
  • a FK garante que a trilha exista;
  • CHECK impede ordem não positiva;
  • UNIQUE impede 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çãoEfeito geralQuando pode representar o domínio
NO ACTIONa operação falha se a violação ainda existir no momento da verificaçãoestado pode ser corrigido antes de uma verificação adiada
RESTRICTbloqueia a alteração que encontra referênciaspai e filho possuem ciclos de vida independentes
CASCADEpropaga exclusão ou atualização aos dependenteso filho é componente e não existe sem o pai
SET NULLmantém o filho e remove a referênciaassociação é opcional e ausência tem significado
SET DEFAULTtroca a referência por um valor padrãoexiste um destino padrão válido e semanticamente correto
Quatro painéis comparam bloqueio, exclusão em cascata, referência nula e referência redirecionada ao padrão após excluir uma linha pai
A ação referencial deve expressar o ciclo de vida. CASCADE não é uma conveniência automática, e SET NULL ou SET DEFAULT continuam sujeitos às demais restrições.

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 ou CHECK;
  • colunas da mesma linha: CHECK de tabela;
  • unicidade entre linhas: UNIQUE ou, 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.
Fluxo relaciona a abrangência de uma regra a tipos, NOT NULL, CHECK, UNIQUE, EXCLUDE, FOREIGN KEY ou mecanismos procedurais
Prefira a restrição declarativa mais específica. Triggers e serviços são úteis para regras que dependem de histórico, agregados ou sistemas externos, mas exigem documentação e testes adicionais.

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:

  1. consulte e quantifique as violações;
  2. defina como corrigir, completar, consolidar ou separar os registros;
  3. aplique a restrição com estratégia compatível com volume e disponibilidade;
  4. valide todo o conjunto, não apenas inserções futuras;
  5. 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:

  1. quais atributos são obrigatórios e por quê;
  2. quais valores e combinações pertencem ao domínio;
  3. qual chave preserva a identidade e quais candidatas também são únicas;
  4. quais participações são obrigatórias ou opcionais;
  5. o que acontece ao atualizar ou excluir cada chave referenciada;
  6. quais filhos são componentes e quais possuem vida própria;
  7. se a regra envolve uma coluna, uma linha, várias linhas ou outro sistema;
  8. se a mensagem e o nome da restrição ajudam a diagnosticar a violação;
  9. como dados existentes serão validados durante a migração;
  10. 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