Tela de computador exibindo linhas de código em um editor
As chaves permitem identificar registros e representar relações sem repetir informações. Crédito da foto.
Compartilhe este conteúdo

A chave primária identifica cada linha de uma tabela sem ambiguidade. A chave estrangeira guarda um valor que aponta para uma linha existente em outra tabela. Juntas, elas permitem relacionar dados e impedir situações inválidas, como cadastrar um pedido para um cliente que não existe.

Chave primária: a identidade da linha

Imagine uma tabela de clientes com duas pessoas chamadas Ana Souza. O nome não permite saber qual delas realizou um pedido. Precisamos de um valor exclusivo e obrigatório para identificar cada registro.

CREATE TABLE clientes (
    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    nome VARCHAR(120) NOT NULL,
    email VARCHAR(150) UNIQUE NOT NULL
);

Nesse exemplo, id é a chave primária. No PostgreSQL, a declaração PRIMARY KEY exige valores únicos e não nulos. A tabela possui apenas uma chave primária, embora essa chave possa envolver mais de uma coluna.

Chave natural ou substituta?

Uma chave natural já possui significado no mundo real, como uma matrícula institucional. Uma chave substituta é criada apenas para identificação interna, como um número sequencial. A escolha depende de estabilidade, tamanho e regras do domínio.

  • Natural: pode tornar o dado mais reconhecível, mas precisa ser realmente único, obrigatório e estável.
  • Substituta: simplifica referências e evita depender de um dado externo que possa mudar.

Mesmo quando usamos um id interno, regras naturais continuam importantes. O e-mail do exemplo possui UNIQUE porque a aplicação decidiu não aceitar dois clientes com o mesmo endereço.

Chave composta

Uma chave composta utiliza mais de uma coluna. Em uma tabela que registra a participação de produtos em pedidos, a combinação entre pedido e produto pode identificar cada item:

PRIMARY KEY (pedido_id, produto_id)

Cada coluna pode se repetir isoladamente, mas a combinação não. Se o mesmo produto puder aparecer em várias linhas do mesmo pedido, será necessário outro identificador ou um número de item.

Chave estrangeira: a ligação entre tabelas

Agora, cada pedido precisa pertencer a um cliente. Em vez de repetir nome e e-mail do cliente em todos os pedidos, armazenamos o identificador dele:

CREATE TABLE pedidos (
    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    cliente_id INTEGER NOT NULL REFERENCES clientes(id),
    data_pedido DATE NOT NULL,
    status VARCHAR(30) NOT NULL
);

cliente_id é uma chave estrangeira. O banco verifica se o valor existe em clientes(id). Essa garantia é chamada de integridade referencial.

Importante: a chave estrangeira não “copia” a linha do cliente. Ela registra a referência. Para reunir informações das duas tabelas em uma consulta, utilizamos um JOIN.
SELECT pedidos.id, pedidos.data_pedido, clientes.nome
FROM pedidos
JOIN clientes ON clientes.id = pedidos.cliente_id
ORDER BY pedidos.data_pedido DESC;

Como as chaves representam relacionamentos

Um para muitos

Um cliente pode realizar muitos pedidos, mas cada pedido pertence a um cliente. A chave estrangeira fica na tabela do lado “muitos”: pedidos.cliente_id.

Muitos para muitos

Um pedido pode conter vários produtos e um produto pode aparecer em vários pedidos. Criamos uma tabela associativa:

CREATE TABLE produtos (
    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    nome VARCHAR(120) NOT NULL,
    preco NUMERIC(10,2) NOT NULL CHECK (preco >= 0)
);

CREATE TABLE itens_pedido (
    pedido_id INTEGER REFERENCES pedidos(id),
    produto_id INTEGER REFERENCES produtos(id),
    quantidade INTEGER NOT NULL CHECK (quantidade > 0),
    preco_unitario NUMERIC(10,2) NOT NULL,
    PRIMARY KEY (pedido_id, produto_id)
);

A tabela associativa contém duas chaves estrangeiras e dados próprios da relação. Guardar preco_unitario preserva o preço praticado no momento da venda, mesmo que o cadastro do produto seja atualizado depois.

Um para um

Em uma relação 1:1, uma chave estrangeira também precisa ser única. Um exemplo seria separar dados públicos do usuário e configurações privadas:

CREATE TABLE perfis (
    usuario_id INTEGER PRIMARY KEY REFERENCES usuarios(id),
    biografia TEXT
);

A mesma coluna funciona como chave primária e estrangeira, permitindo no máximo um perfil para cada usuário.

O que acontece quando o registro referenciado é excluído?

A regra precisa ser escolhida conforme o significado dos dados:

AçãoComportamentoQuando considerar
NO ACTIONA operação falha se a referência continuar inválidaComportamento padrão e seguro
RESTRICTBloqueia imediatamente a exclusão referenciadaElementos independentes
CASCADEExclui também as linhas dependentesPartes que não existem sem o registro principal
SET NULLRemove a referência e mantém a linhaRelacionamento opcional
pedido_id INTEGER
    REFERENCES pedidos(id)
    ON DELETE CASCADE

Se um pedido for excluído, seus itens podem ser removidos junto porque não possuem significado independente. Já apagar um cliente e todos os seus pedidos automaticamente pode destruir histórico comercial. CASCADE deve representar uma regra consciente, não uma forma de evitar mensagens de erro.

Chave estrangeira cria índice automaticamente?

No PostgreSQL, a chave primária cria um índice único automaticamente. A declaração da chave estrangeira, porém, não cria automaticamente um índice na coluna que faz a referência. Consultas, atualizações e exclusões podem se beneficiar de um índice nessa coluna, mas a decisão deve considerar o uso real.

CREATE INDEX idx_pedidos_cliente_id
ON pedidos (cliente_id);

Erros comuns

  • relacionar tabelas usando nomes em vez de identificadores estáveis;
  • criar chave estrangeira com tipo incompatível com a chave referenciada;
  • permitir nulo quando a relação deveria ser obrigatória;
  • usar CASCADE sem avaliar perda de histórico;
  • repetir dados do cliente em todas as linhas do pedido;
  • esquecer a tabela associativa em relações muitos-para-muitos;
  • confundir UNIQUE com chave primária.

Atividade prática

Crie as tabelas autores, livros e livros_autores. Um livro pode ter vários autores e um autor pode escrever vários livros. Defina chaves primárias e estrangeiras, impeça a repetição do mesmo autor no mesmo livro e explique qual regra de exclusão você adotaria.

Perguntas frequentes

Toda tabela precisa de chave primária?

O PostgreSQL permite criar uma tabela sem ela, mas no modelo relacional é uma boa prática identificar cada linha. Sem identificação confiável, atualizar, excluir ou relacionar registros se torna mais arriscado.

Uma tabela pode ter várias chaves estrangeiras?

Sim. Uma tabela pode se relacionar com várias outras e até possuir mais de uma referência para a mesma tabela, desde que cada relação tenha significado claro.

Chave estrangeira pode aceitar NULL?

Pode, quando o relacionamento for opcional. Se a referência for obrigatória, declare também NOT NULL.

Referências bibliográficas

Obras reconhecidas que fundamentam e aprofundam os conceitos apresentados neste artigo.

  1. ELMASRI, Ramez; NAVATHE, Shamkant B. Fundamentals of Database Systems. 7. ed. Pearson, 2016.
  2. SILBERSCHATZ, Abraham; KORTH, Henry F.; SUDARSHAN, S. Database System Concepts. 7. ed. McGraw-Hill Education, 2020.

Documentação técnica: PostgreSQL Global Development Group. Constraints. Acesso em 22 ago. 2026.

Consulte a bibliografia completa do Código em Sala.