FOREIGN KEY: relacionando tabelas
1. O que é uma FOREIGN KEY e por que ela existe?
Uma FOREIGN KEY (chave estrangeira) é um mecanismo fundamental em bancos de dados relacionais que estabelece um vínculo entre duas tabelas. Conceitualmente, funciona como uma "ponte" que conecta registros de uma tabela (tabela filha) a registros de outra tabela (tabela pai), garantindo que os dados relacionados existam e sejam consistentes.
A principal função da FOREIGN KEY é assegurar a integridade referencial dos dados. Isso significa que, se uma coluna em uma tabela referencia um valor existente em outra tabela, o banco de dados não permitirá que esse valor referenciado seja excluído ou alterado de forma que quebre o relacionamento.
A diferença fundamental entre chave primária (PRIMARY KEY) e chave estrangeira é:
- PRIMARY KEY: identifica unicamente cada registro em uma tabela. Não permite valores nulos ou duplicados.
- FOREIGN KEY: referencia a chave primária de outra tabela. Pode conter valores nulos e duplicados, dependendo da regra de negócio.
2. Sintaxe básica para criar FOREIGN KEY
Criando FOREIGN KEY na criação da tabela
CREATE TABLE clientes (
id_cliente INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE
);
CREATE TABLE pedidos (
id_pedido INT PRIMARY KEY,
data_pedido DATE NOT NULL,
valor_total DECIMAL(10,2),
id_cliente INT,
FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente)
);
Adicionando FOREIGN KEY em tabela existente
ALTER TABLE pedidos
ADD CONSTRAINT fk_pedidos_clientes
FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente);
A sintaxe completa segue o padrão: FOREIGN KEY (coluna_filha) REFERENCES tabela_pai(coluna_pai). A constraint pode receber um nome personalizado (como fk_pedidos_clientes) para facilitar futuras manutenções.
3. Regras de integridade referencial: ON DELETE e ON UPDATE
As cláusulas ON DELETE e ON UPDATE definem o comportamento do banco de dados quando um registro pai é excluído ou atualizado.
ON DELETE CASCADE
Remove automaticamente todos os registros filhos quando o registro pai é excluído.
CREATE TABLE pedidos (
id_pedido INT PRIMARY KEY,
id_cliente INT,
FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente)
ON DELETE CASCADE
);
ON DELETE SET NULL
Define a coluna FK como NULL quando o registro pai é excluído, mantendo o registro filho órfão.
FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente)
ON DELETE SET NULL
ON DELETE RESTRICT e NO ACTION
Impedem a exclusão do registro pai se existirem registros filhos relacionados. A diferença entre eles é sutil e depende do SGBD: RESTRICT verifica imediatamente, enquanto NO ACTION pode adiar a verificação.
FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente)
ON DELETE RESTRICT
Os mesmos comportamentos se aplicam ao ON UPDATE, controlando o que acontece quando a chave primária do registro pai é alterada.
4. Exemplo prático: modelando um sistema de pedidos
Vamos construir um sistema completo de pedidos com integridade referencial:
-- Criação da tabela clientes
CREATE TABLE clientes (
id_cliente INT AUTO_INCREMENT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
data_cadastro DATE DEFAULT CURRENT_DATE
);
-- Criação da tabela pedidos com FOREIGN KEY
CREATE TABLE pedidos (
id_pedido INT AUTO_INCREMENT PRIMARY KEY,
data_pedido DATETIME DEFAULT CURRENT_TIMESTAMP,
valor_total DECIMAL(10,2) NOT NULL,
id_cliente INT NOT NULL,
FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente)
ON DELETE RESTRICT
);
-- Inserindo dados válidos
INSERT INTO clientes (nome, email) VALUES
('Maria Silva', 'maria@email.com'),
('João Santos', 'joao@email.com');
INSERT INTO pedidos (valor_total, id_cliente) VALUES
(150.00, 1),
(89.90, 2);
-- Tentativa de inserir pedido com cliente inexistente (ERRO!)
INSERT INTO pedidos (valor_total, id_cliente) VALUES (200.00, 99);
-- Erro: Cannot add or update a child row: a foreign key constraint fails
O banco de dados rejeitará a inserção do pedido com id_cliente = 99 porque não existe nenhum cliente com esse identificador, protegendo a integridade dos dados.
5. Relacionamentos mais complexos com múltiplas FOREIGN KEYs
FK composta referenciando chave primária composta
CREATE TABLE turmas (
id_curso INT,
id_turma INT,
PRIMARY KEY (id_curso, id_turma)
);
CREATE TABLE matriculas (
id_matricula INT PRIMARY KEY,
id_curso INT,
id_turma INT,
id_aluno INT,
FOREIGN KEY (id_curso, id_turma) REFERENCES turmas(id_curso, id_turma)
);
Auto-referência (hierarquia de funcionários)
CREATE TABLE funcionarios (
id_funcionario INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
id_gestor INT,
FOREIGN KEY (id_gestor) REFERENCES funcionarios(id_funcionario)
);
Tabela associativa para relacionamento N:N
CREATE TABLE alunos (
id_aluno INT PRIMARY KEY,
nome VARCHAR(100)
);
CREATE TABLE cursos (
id_curso INT PRIMARY KEY,
nome_curso VARCHAR(100)
);
CREATE TABLE alunos_cursos (
id_aluno INT,
id_curso INT,
data_matricula DATE,
PRIMARY KEY (id_aluno, id_curso),
FOREIGN KEY (id_aluno) REFERENCES alunos(id_aluno),
FOREIGN KEY (id_curso) REFERENCES cursos(id_curso)
);
6. Boas práticas e armadilhas comuns
Indexação de FOREIGN KEY: A maioria dos SGBDs não cria índices automaticamente nas colunas FK. É recomendável criá-los manualmente para melhorar performance em JOINs:
CREATE INDEX idx_pedidos_cliente ON pedidos(id_cliente);
Cuidado com cascatas infinitas: Em tabelas com auto-referência ou relacionamentos circulares, CASCADE pode criar loops infinitos. Sempre teste cenários de exclusão antes de implementar em produção.
Evitar FK em colunas voláteis: Prefira chaves primárias estáveis (como IDs numéricos) em vez de colunas que mudam com frequência (como CPF ou email), pois alterações na PK pai podem propagar atualizações indesejadas.
Documentação: Mantenha um diagrama ou documentação textual dos relacionamentos. Em projetos complexos, isso economiza horas de debugging.
7. Consultando dados entre tabelas com FOREIGN KEY
INNER JOIN usando FK
SELECT c.nome, p.id_pedido, p.valor_total
FROM clientes c
INNER JOIN pedidos p ON c.id_cliente = p.id_cliente;
LEFT JOIN para encontrar registros órfãos
SELECT p.id_pedido, p.id_cliente
FROM pedidos p
LEFT JOIN clientes c ON p.id_cliente = c.id_cliente
WHERE c.id_cliente IS NULL;
Verificando integridade referencial
-- Encontrar pedidos sem cliente correspondente
SELECT * FROM pedidos
WHERE id_cliente NOT IN (SELECT id_cliente FROM clientes);
8. Gerenciando FOREIGN KEY no dia a dia
Removendo uma FOREIGN KEY
ALTER TABLE pedidos DROP FOREIGN KEY fk_pedidos_clientes;
Desabilitando verificações temporariamente (MySQL)
SET FOREIGN_KEY_CHECKS = 0;
-- Operações que violariam integridade
SET FOREIGN_KEY_CHECKS = 1;
Risco: Desabilitar verificações pode corromper a integridade dos dados. Use apenas em migrações controladas e sempre restaure as verificações imediatamente.
Adicionando FK em tabela com dados existentes
Antes de adicionar a constraint, limpe dados inconsistentes:
-- Identificar registros problemáticos
DELETE FROM pedidos WHERE id_cliente NOT IN (SELECT id_cliente FROM clientes);
-- Agora é seguro adicionar a FK
ALTER TABLE pedidos
ADD CONSTRAINT fk_pedidos_clientes
FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente);
As FOREIGN KEYs são a espinha dorsal da integridade referencial em bancos de dados relacionais. Dominar sua sintaxe, comportamentos e armadilhas é essencial para construir sistemas robustos e confiáveis. Lembre-se: uma FK bem projetada previne inconsistências antes que elas aconteçam, economizando horas de correção de dados no futuro.
Referências
- MySQL Documentation: FOREIGN KEY Constraints — Documentação oficial do MySQL com sintaxe completa, exemplos e comportamentos de ON DELETE e ON UPDATE.
- PostgreSQL Documentation: Foreign Keys — Guia oficial do PostgreSQL sobre chaves estrangeiras, incluindo diferenças de implementação entre SGBDs.
- SQL Server Documentation: FOREIGN KEY Constraints — Documentação da Microsoft com exemplos práticos e considerações de performance para SQL Server.
- Oracle Documentation: Foreign Key Constraints — Referência completa da Oracle sobre constraints, incluindo FOREIGN KEY com exemplos avançados.
- W3Schools SQL FOREIGN KEY Tutorial — Tutorial interativo com exemplos práticos e exercícios para iniciantes em SQL.
- SQLShack: Understanding Foreign Keys in SQL Server — Artigo técnico detalhado sobre implementação, manutenção e troubleshooting de chaves estrangeiras.