Menu

Chaves Primárias no SQLite: INTEGER, Composta e AUTOINCREMENT

Como funcionam as chaves primárias no SQLite: o famoso INTEGER PRIMARY KEY, chaves compostas, AUTOINCREMENT e as armadilhas que pegam quem está começando.

Esta página tem editores executáveis — edite, execute e veja a saída na hora.

O que a chave primária realmente faz

A chave primária é a coluna (ou conjunto de colunas) que identifica cada linha da tabela de forma única. Duas linhas nunca podem ter o mesmo valor de chave primária. O SQLite garante isso automaticamente e ainda usa essa chave para localizar registros rapidamente.

A forma mais simples vai direto na declaração da coluna:

Você não passou um id e mesmo assim o SQLite preencheu um pra você. Isso não é mágica — é um comportamento especial do INTEGER PRIMARY KEY que vale a pena entender antes de escrever qualquer outra coisa.

Por que INTEGER PRIMARY KEY é especial no SQLite

Na maioria dos bancos, uma chave primária é só um índice único. No SQLite, toda tabela comum já tem um inteiro de 64 bits escondido chamado rowid, que identifica as linhas internamente. Quando você declara uma coluna exatamente como INTEGER PRIMARY KEY, essa coluna vira o rowid. Sem índice extra, sem armazenamento extra — seu id e a localização física da linha são a mesma coisa.

id e rowid são a mesma coluna com dois nomes diferentes. Quando você busca por id, a consulta vai direto na linha — não tem uma segunda árvore para percorrer. Por isso a recomendação padrão no SQLite é: se você quer uma chave primária numérica, escreva INTEGER PRIMARY KEY exatamente assim. Não vale INT, nem BIGINT, nem INTEGER NOT NULL PRIMARY KEY (esse até funciona, mas o tipo precisa ser INTEGER).

Outros tipos também funcionam — só que aí o SQLite cria um índice único separado. Não tem nada de errado nisso, só fica menos compacto.

Quando usar AUTOINCREMENT no SQLite (spoiler: quase nunca)

Quem vem de outros bancos costuma escrever id INTEGER PRIMARY KEY AUTOINCREMENT no automático. Só que no SQLite a palavra-chave AUTOINCREMENT faz algo bem mais restrito do que o nome dá a entender, e na maioria dos casos você não precisa dela.

Sem AUTOINCREMENT, uma coluna INTEGER PRIMARY KEY é preenchida automaticamente com o maior rowid existente mais um. Se você apagar a última linha, o próximo insert pode reaproveitar aquele id.

Com AUTOINCREMENT, o SQLite passa a registrar o maior id já utilizado numa tabela auxiliar chamada sqlite_sequence e nunca reaproveita valores, mesmo depois de exclusões.

A tabela plain reaproveitou o id 3. Já a tabela com AUTOINCREMENT pulou para 4. A não ser que você tenha um motivo real para proibir o reuso de ids — auditoria, referências externas que continuam existindo depois de um delete — esqueça o AUTOINCREMENT. Ele custa uma gravação extra por insert e ainda mantém uma tabela auxiliar só para esse controle.

Chave primária composta no SQLite

Às vezes uma única coluna não dá conta do recado. Uma tabela de junção que liga usuários a papéis, por exemplo, é identificada de forma única pelo par (user_id, role_id). Nesses casos, declare a chave primária composta no nível da tabela:

O par precisa ser único em toda a tabela — (1, 10) só pode aparecer uma vez. Cada coluna isolada pode se repetir à vontade. É justamente esse o objetivo: cada usuário pode ter vários papéis, cada papel pode ter vários usuários, mas uma combinação específica usuário-papel existe no máximo uma vez.

Uma chave primária composta no SQLite cria um índice próprio cobrindo as colunas listadas. Ela não vira o rowid — só uma INTEGER PRIMARY KEY recebe esse tratamento especial.

A pegadinha do NULL em chave primária

Aqui vai uma esquisitice que pega de surpresa quem vem do PostgreSQL ou do MySQL: numa tabela SQLite comum, uma coluna de chave primária que não seja INTEGER PRIMARY KEY pode conter NULL. É um bug antigo que os autores do SQLite mantiveram por questões de compatibilidade.

Duas linhas com NULL passaram batido pela chave primária. Para resolver, basta adicionar NOT NULL explicitamente em toda coluna de chave primária que não seja integer:

Ou então use uma tabela STRICT, onde o bug de NULL na PK foi corrigido. Acostumar-se a escrever NOT NULL em toda coluna de chave primária é um seguro barato.

Primary key vs UNIQUE no SQLite

As duas evitam duplicatas. As diferenças são:

  • Uma tabela tem no máximo uma chave primária, mas pode ter várias constraints UNIQUE.
  • A chave primária é o identificador "principal" da tabela — é para ela que as foreign keys apontam por padrão.
  • Um INTEGER PRIMARY KEY vira o rowid; já uma coluna inteira com UNIQUE não.
  • Colunas UNIQUE aceitam vários NULL numa boa (cada NULL é considerado distinto).

id é a identidade da linha. email e username também são únicos, mas são atributos de negócio — podem mudar com o tempo, enquanto o id não deveria.

Adicionando uma chave primária depois (em geral: não faça isso)

O ALTER TABLE do SQLite é limitado. Não dá pra rodar ALTER TABLE ... ADD PRIMARY KEY — esse comando simplesmente não existe. Se você esqueceu de definir a chave primária e a tabela já tem dados, o jeito é recriar a tabela:

Esse é o passinho clássico de migração no SQLite. Em código de produção, envolva tudo numa transação e, se outras tabelas referenciarem esta, desative as foreign keys por um instante. A lição que fica: acerte a chave primária já na hora do CREATE TABLE.

Um checklist rápido

Ao criar uma tabela nova, se pergunte:

  • Essa linha tem um identificador único natural? Se for um único inteiro, use INTEGER PRIMARY KEY.
  • A identidade é, na verdade, uma combinação de colunas (tabela de junção)? Use uma chave primária composta no nível da tabela: PRIMARY KEY (col_a, col_b).
  • A chave é texto ou outro tipo que não seja inteiro? Coloque NOT NULL explicitamente.
  • Você realmente precisa de AUTOINCREMENT? Provavelmente não.
  • A tabela é pequena, majoritariamente lida e tem chave primária não-inteira? Vale considerar WITHOUT ROWID (assunto do doc sobre rowid).

A seguir: rowid

O INTEGER PRIMARY KEY apareceu rapidinho como "um apelido para o rowid" — mas o rowid é a base que sustenta toda tabela comum no SQLite, e merece ser entendido por conta própria. É exatamente o tema da próxima página.

Perguntas frequentes

Como defino uma chave primária no SQLite?

Basta adicionar PRIMARY KEY em uma coluna dentro do CREATE TABLE, por exemplo id INTEGER PRIMARY KEY. Se você precisa de uma chave que abrange várias colunas, use a restrição em nível de tabela: PRIMARY KEY (col_a, col_b). A coluna (ou a combinação delas) precisa ser única em todas as linhas.

Qual a diferença entre INTEGER PRIMARY KEY e outras chaves primárias no SQLite?

O INTEGER PRIMARY KEY é um caso especial: ele vira um apelido para o rowid interno da tabela, ou seja, fica armazenado direto na B-tree, sem índice extra. Qualquer outro tipo, ou uma chave composta, gera um índice único separado. Para ids numéricos de coluna única, INTEGER PRIMARY KEY é mais rápido e ocupa menos espaço.

Preciso usar AUTOINCREMENT na chave primária do SQLite?

Geralmente não. Uma coluna INTEGER PRIMARY KEY já atribui um rowid único automaticamente quando você insere NULL. O AUTOINCREMENT só acrescenta a garantia de que ids nunca serão reaproveitados depois de um delete — e isso tem o custo de manter uma tabela sqlite_sequence extra. Só use se você realmente precisa desse comportamento de id sempre crescente.

Por que minha chave primária no SQLite está aceitando NULL?

É um bug histórico, mantido por compatibilidade: em tabelas comuns, uma coluna de chave primária que não seja INTEGER aceita NULL a menos que você declare explicitamente NOT NULL. A exceção é a coluna INTEGER PRIMARY KEY, que nunca aceita NULL. Para evitar dor de cabeça, escreva NOT NULL em toda coluna de chave primária — ou use uma tabela STRICT, onde a regra é aplicada de verdade.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR