Chave estrangeira e integridade referencial na Modelagem de Dados: consistência e regras

Capítulo 8

Tempo estimado de leitura: 9 minutos

+ Exercício

O que é chave estrangeira (FK) e por que ela existe

Chave estrangeira (foreign key) é uma restrição no banco de dados que faz um atributo (ou conjunto de atributos) em uma tabela apontar para uma chave (normalmente a chave primária, mas pode ser uma chave única) de outra tabela. Ela é o mecanismo que implementa relacionamentos no nível físico e garante integridade referencial: um registro “filho” só pode referenciar um registro “pai” que realmente exista.

Em termos práticos, a FK impede que você grave valores inválidos em colunas de referência e define o que deve acontecer quando o registro referenciado é atualizado ou excluído.

Exemplo base (Cliente e Pedido)

CLIENTE(id_cliente PK, nome, ...)
PEDIDO(id_pedido PK, id_cliente FK, data_pedido, ...)

A regra de integridade referencial aqui é: PEDIDO.id_cliente deve existir em CLIENTE.id_cliente (ou ser nulo, se o relacionamento permitir).

Como a FK garante integridade referencial

  • Na inserção: impede inserir um filho apontando para um pai inexistente.
  • Na atualização do valor da FK: impede trocar a referência para um pai inexistente.
  • Na exclusão do pai: impede (ou trata) a exclusão quando existem filhos dependentes.
  • Na atualização da chave do pai (menos comum, mas possível): impede (ou trata) a atualização quando existem filhos referenciando.

Esses comportamentos são controlados por ações ON DELETE e ON UPDATE na definição da FK.

Passo a passo prático: definindo uma FK com ações

1) Confirme a coluna referenciada

A coluna no “pai” precisa ser chave primária ou ter restrição de unicidade (por exemplo, UNIQUE). Exemplo: CLIENTE.id_cliente é PK.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

2) Defina o domínio compatível

O tipo e o domínio do campo FK devem ser compatíveis com o campo referenciado (mesmo tipo, tamanho e semântica). Ex.: ambos INT ou ambos UUID.

3) Decida se a FK pode ser nula

Se o relacionamento for opcional do lado do filho, a coluna FK pode aceitar NULL. Se for obrigatório, use NOT NULL.

4) Escolha as ações de integridade (DELETE/UPDATE)

As ações devem refletir a regra de negócio: o que acontece com os filhos quando o pai muda ou é removido.

5) Crie a restrição

ALTER TABLE PEDIDO ADD CONSTRAINT fk_pedido_cliente FOREIGN KEY (id_cliente) REFERENCES CLIENTE(id_cliente) ON DELETE RESTRICT ON UPDATE RESTRICT;

O exemplo acima impede excluir/alterar um cliente se houver pedidos associados.

Comportamentos em operações: RESTRICT/NO ACTION, CASCADE, SET NULL, SET DEFAULT

As ações abaixo podem ser usadas em ON DELETE e ON UPDATE. A escolha não é “técnica”, é uma decisão de regra de negócio e de preservação de histórico.

AçãoO que fazQuando faz sentidoRiscos/atenções
RESTRICT / NO ACTIONBloqueia a operação no pai se existirem filhos referenciando.Quando o filho não pode existir sem o pai e você não quer apagar/alterar automaticamente. Ex.: não permitir excluir CLIENTE com PEDIDO.Exige fluxo de negócio explícito: primeiro tratar filhos (cancelar, arquivar, transferir), depois excluir/alterar pai.
CASCADEPropaga a exclusão/atualização do pai para os filhos.Quando o filho é estritamente dependente e não tem significado sem o pai. Ex.: ITEM_PEDIDO deve ser removido ao excluir PEDIDO.Risco de apagar/alterar grandes volumes sem perceber. Pode causar “efeito dominó” em cadeias de FKs.
SET NULLAo excluir/alterar o pai, define a FK do filho como NULL.Quando o relacionamento é opcional e o filho pode continuar existindo sem o pai. Ex.: TAREFA pode ficar sem RESPONSAVEL.A coluna FK precisa aceitar NULL. Pode gerar registros “sem dono” que exigem tratamento (fila de reatribuição).
SET DEFAULTAo excluir/alterar o pai, define a FK do filho para um valor padrão.Quando existe um “pai padrão” válido. Ex.: reatribuir para CLIENTE “Não identificado” ou USUARIO “Sistema”.O valor default deve existir no pai; caso contrário, a operação falha. Pode mascarar problemas se usado sem critério.

RESTRICT vs NO ACTION (nota prática)

Em muitos SGBDs, RESTRICT e NO ACTION se comportam de forma muito semelhante. A diferença costuma aparecer em cenários de verificação adiada (deferred constraints) ou no momento exato da checagem dentro da transação. Como regra geral de modelagem, trate ambos como “não deixe fazer se houver dependentes”, e valide o comportamento específico do seu SGBD quando usar transações complexas.

Entidades dependentes e consequências para exclusão/atualização

Uma entidade dependente é aquela cuja existência está amarrada a outra. No banco, isso normalmente se manifesta por uma FK obrigatória (NOT NULL) e, em muitos casos, por uma estratégia de exclusão/atualização coerente com essa dependência.

Exemplo 1: Pedido e Item do Pedido (dependência forte)

PEDIDO(id_pedido PK, ...)
ITEM_PEDIDO(id_pedido FK, nro_item, produto, qtd, ...)

Regra típica: não existe item sem pedido. Aqui, ON DELETE CASCADE em ITEM_PEDIDO costuma fazer sentido, porque excluir um pedido deve remover seus itens.

ALTER TABLE ITEM_PEDIDO ADD CONSTRAINT fk_item_pedido FOREIGN KEY (id_pedido) REFERENCES PEDIDO(id_pedido) ON DELETE CASCADE ON UPDATE RESTRICT;

Por que não CASCADE no UPDATE? Em geral, chaves primárias não deveriam mudar. Se mudarem, CASCADE no update pode propagar alterações amplas. Muitas equipes preferem impedir (RESTRICT) e tratar como operação excepcional.

Exemplo 2: Usuário e Tarefa (dependência fraca/opcional)

USUARIO(id_usuario PK, ...)
TAREFA(id_tarefa PK, id_responsavel FK NULL, ...)

Se ao excluir um usuário as tarefas devem continuar existindo para reatribuição, use SET NULL:

ALTER TABLE TAREFA ADD CONSTRAINT fk_tarefa_usuario FOREIGN KEY (id_responsavel) REFERENCES USUARIO(id_usuario) ON DELETE SET NULL ON UPDATE RESTRICT;

Exemplo 3: “Pai padrão” (SET DEFAULT)

Suponha que pedidos possam existir associados a um cliente “genérico” (por exemplo, vendas balcão). Você pode definir id_cliente com default para o cliente “Balcão” (que deve existir em CLIENTE).

-- CLIENTE(0, 'Balcão') existe previamente
ALTER TABLE PEDIDO ALTER COLUMN id_cliente SET DEFAULT 0;
ALTER TABLE PEDIDO ADD CONSTRAINT fk_pedido_cliente FOREIGN KEY (id_cliente) REFERENCES CLIENTE(id_cliente) ON DELETE SET DEFAULT ON UPDATE RESTRICT;

Esse padrão é útil quando a regra de negócio exige manter o registro do filho sempre associado a algum pai válido, mesmo após exclusões.

Erros comuns e como preveni-los

1) Registros órfãos (filhos sem pai)

Como acontece: ausência de FK, ou FK desabilitada, ou carga de dados “na mão” sem validação. Ex.: inserir PEDIDO.id_cliente = 999 sem existir CLIENTE(999).

Como prevenir:

  • Crie FKs em todas as colunas de referência reais.
  • Evite “validar na aplicação” como único mecanismo; o banco deve garantir.
  • Em migrações/cargas, carregue primeiro os pais e depois os filhos.

Como detectar (consulta típica):

SELECT p.* FROM PEDIDO p LEFT JOIN CLIENTE c ON c.id_cliente = p.id_cliente WHERE c.id_cliente IS NULL;

2) Inconsistência por ação inadequada (CASCADE perigoso)

Como acontece: usar ON DELETE CASCADE em relacionamentos que deveriam preservar histórico. Ex.: excluir CLIENTE e apagar automaticamente PEDIDO, perdendo rastreabilidade.

Como prevenir:

  • Para entidades de histórico (pedido, nota, pagamento), prefira RESTRICT/NO ACTION e trate exclusão como “inativação” (quando aplicável ao domínio).
  • Se CASCADE for necessário, limite-o a dependências claramente “componentes” (ex.: itens do pedido).
  • Mapeie cadeias de FKs para evitar cascatas em múltiplos níveis sem intenção.

3) Usar SET NULL em coluna NOT NULL

Como acontece: definir ON DELETE SET NULL mas a coluna FK foi criada como NOT NULL. Resultado: a exclusão do pai falha.

Como prevenir:

  • Alinhe opcionalidade: se a ação é SET NULL, a coluna deve permitir NULL.
  • Valide a regra: o filho pode existir sem pai? Se não, não use SET NULL.

4) SET DEFAULT sem “pai default” válido

Como acontece: definir SET DEFAULT mas o default não existe na tabela pai, ou o default não foi definido na coluna.

Como prevenir:

  • Crie e proteja o registro “default” no pai (e.g., cliente balcão).
  • Garanta que o default esteja definido na coluna FK e seja compatível com o domínio.

5) Referenciar coluna não única no pai

Como acontece: tentar criar FK apontando para uma coluna que não é PK nem UNIQUE. Isso quebra a garantia de “um pai identificável”.

Como prevenir:

  • Referencie PK ou uma chave alternativa com UNIQUE.
  • Se a regra de negócio pede referência por um identificador natural, imponha unicidade nele antes de referenciar.

6) Atualização de chave do pai sem estratégia (ON UPDATE)

Como acontece: permitir que o valor referenciado mude sem definir ON UPDATE adequado, causando falha na atualização ou inconsistência se a FK não existir.

Como prevenir:

  • Evite atualizar chaves primárias; trate como imutáveis sempre que possível.
  • Se a atualização for necessária (ex.: chave natural que pode mudar), avalie ON UPDATE CASCADE com cautela e testes.
  • Prefira chaves substitutas para reduzir a necessidade de updates em chaves referenciadas.

Checklist rápido para escolher a ação correta

  • Filho não pode existir sem pai: FK NOT NULL e geralmente ON DELETE RESTRICT (se quer bloquear) ou ON DELETE CASCADE (se quer apagar junto).
  • Filho pode existir sem pai: FK permite NULL e ON DELETE SET NULL.
  • Filho deve sempre apontar para algum pai válido, mesmo após exclusão: ON DELETE SET DEFAULT com “pai padrão” existente.
  • Preservar histórico: evite cascata do pai para entidades históricas; prefira bloquear e tratar por processo.
  • Chave do pai não deve mudar: ON UPDATE RESTRICT/NO ACTION.

Agora responda o exercício sobre o conteúdo:

Ao escolher a ação de integridade em uma chave estrangeira, quando faz sentido usar ON DELETE SET NULL?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Use SET NULL quando o filho pode permanecer sem o pai (relação opcional). Nesse caso, a FK deve permitir NULL, pois ao excluir o pai o banco definirá a referência do filho como nula.

Próximo capitúlo

Regras de Negócio na Modelagem de Dados: como capturar, documentar e validar

Arrow Right Icon
Capa do Ebook gratuito Modelagem de Dados do Zero: Entidades, Relacionamentos e Regras de Negócio
50%

Modelagem de Dados do Zero: Entidades, Relacionamentos e Regras de Negócio

Novo curso

16 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.