CREATE TABLE define um esquema
No SQLite, todo dado estruturado mora dentro de uma tabela, e toda tabela nasce de um comando CREATE TABLE. Você dá um nome, lista as colunas e, se quiser, adiciona algumas constraints. O SQLite grava o esquema no arquivo do banco e pronto: a tabela já está disponível para uso.
Veja o exemplo mais simples que vale a pena mostrar:
Três colunas, uma chave primária e uma regra NOT NULL. O SQLite preencheu o id automaticamente porque é uma chave primária inteira, e deixou o email ficar NULL na segunda linha já que ninguém disse o contrário. Essa é a estrutura toda — nome, colunas, constraints — e tudo o mais nesta página é variação em cima disso.
Sintaxe do CREATE TABLE no SQLite, parte por parte
A definição de uma coluna segue o formato nome TIPO constraint constraint .... O tipo é opcional no SQLite clássico (falo mais sobre isso na página de type affinity), mas é boa prática sempre informar um — quem lê o código e as ferramentas dependem disso.
Alguns detalhes que vale destacar:
- As constraints se encadeiam separadas por espaço:
NOT NULL UNIQUEemskuaplica as duas regras de uma vez. - O
DEFAULT 1emin_stockpermite que oINSERTignore essa coluna. - O SQLite usa
INTEGERpara booleanos — não existe um tipoBOOLEANnativo.0é falso,1é verdadeiro. - Vírgula sobrando depois da última coluna é erro de sintaxe. O SQL é mais rígido que o JavaScript nesse ponto.
IF NOT EXISTS: evite quebrar quando rodar de novo
Se você executar um CREATE TABLE num banco que já tem aquela tabela, o SQLite dispara um erro:
Erro: a tabela users já existe
Tudo bem da primeira vez, mas vira um saco na centésima. O IF NOT EXISTS faz o comando virar um no-op quando a tabela já existe:
O segundo CREATE TABLE simplesmente não faz nada — sem erro, sem alteração no schema. É essa a forma que você quer usar em código de inicialização, scripts de migração e em qualquer lugar onde o mesmo SQL pode acabar rodando mais de uma vez.
Mas atenção: o IF NOT EXISTS só verifica o nome. Se já existir uma tabela com esse nome mas com colunas diferentes, o SQLite deixa ela quietinha como está. Ele não vai "corrigir" nem "atualizar" seu schema. Para isso existem as migrations.
Constraints no SQLite: regras que andam junto com o schema
As constraints são a forma de levar a validação para dentro do próprio banco. As quatro que você vai usar o tempo todo:
PRIMARY KEY— identifica de forma única cada linha. Tem mais detalhe na doc sobre chaves primárias.NOT NULL— a coluna obrigatoriamente precisa ter um valor.DEFAULT valor— entra em ação quando oINSERTnão informa a coluna. Pode ser um literal ou uma expressão tipodatetime('now').CHECK (expr)— precisa ser verdadeira para toda linha.UNIQUE (col, col)— constraint de tabela que garante unicidade na combinação de colunas.
As constraints são verificadas em todo INSERT e UPDATE. Se uma linha violar alguma regra, ela é rejeitada e o comando falha. Barrar dados ruins direto no banco sai bem mais barato do que descobrir o problema depois que ele já se espalhou pela aplicação.
Foreign key no SQLite
Uma foreign key diz o seguinte: "essa coluna aponta para uma linha em outra tabela". Isso mantém seus dados consistentes — você não consegue referenciar um usuário que não existe e, com as opções certas, apagar um usuário pode cascatear a remoção dos pedidos dele.
Uma pegadinha do SQLite que vale memorizar: a checagem de foreign keys vem desligada por padrão. Você precisa executar PRAGMA foreign_keys = ON em toda conexão que quiser ter as constraints validadas. A maioria dos drivers de aplicação já faz isso automaticamente ou expõe alguma configuração; se o seu não fizer, rode esse pragma logo depois de abrir a conexão.
O ON DELETE CASCADE aqui significa que, ao apagar um usuário, os posts dele somem junto. Outras opções são SET NULL, RESTRICT e o padrão — NO ACTION — que bloqueia o delete caso existam registros filhos.
CREATE TABLE AS SELECT no SQLite
Às vezes você só quer uma cópia rápida do resultado de uma query como uma nova tabela — pra fazer um snapshot, um backup ou uma tabela temporária durante uma análise. É aí que entra o CREATE TABLE ... AS SELECT:
A nova tabela herda os nomes das colunas, os tipos (na medida do possível) e os dados. Mas o que ela não copia é igualmente importante: nada de primary key, nada de NOT NULL, nem índices, nem foreign keys. É só um snapshot achatado. Use isso como ponto de partida para trabalhos pontuais, não como forma de clonar um schema de verdade.
Se você quiser apenas a estrutura, sem os dados, basta acrescentar WHERE 0:
Você ganha uma tabela vazia com a mesma estrutura de colunas — útil para tabelas de arquivo que você vai popular depois.
Tabelas temporárias no SQLite
Uma tabela TEMP existe apenas durante a conexão atual com o banco. Ao fechar a conexão, ela some — sem precisar limpar nada, sem schema sobrando:
Bons usos: preparar linhas para uma consulta de várias etapas, guardar resultados intermediários bagunçados demais para uma CTE, ou isolar dados por conexão em uma sessão longa. CREATE TEMP TABLE e CREATE TEMPORARY TABLE significam exatamente a mesma coisa.
Dá para combinar com AS SELECT também: CREATE TEMP TABLE snapshot AS SELECT ... é um padrão comum para congelar um resultado no meio de uma análise.
Aspas em nomes
Na maioria dos casos, nomes de colunas e tabelas são identificadores simples, sem nada em volta. Mas se você precisar usar uma palavra reservada ou um nome com espaços, envolva em aspas duplas (o padrão SQL) ou em crases (uma herança do MySQL que o SQLite também aceita):
Funciona, claro, mas vira um atrito toda vez que você precisa referenciar a tabela. Prefira nomes simples como orders, selection, user_id e esqueça as aspas.
Um exemplo realista de create table no SQLite
Juntando tudo o que vimos — um esquema enxuto para um app de tarefas, usando IF NOT EXISTS para rodar tranquilo em toda inicialização:
Esse esquema já está pronto pra produção: criação idempotente, chaves estrangeiras ativas, um CHECK mantendo o done na linha, defaults sensatos e timestamps que se preenchem sozinhos.
Próximo: Tipos de Dados
O CREATE TABLE permite escrever INTEGER, TEXT, REAL — mas o SQLite é conhecido por ser bem flexível na hora de armazenar esses valores. A próxima página fala sobre as cinco classes de armazenamento que o SQLite realmente usa por baixo dos panos, e por que o tipo que você declarou nem sempre é o tipo que você recebe.
Perguntas frequentes
Como criar uma tabela no SQLite?
Use CREATE TABLE nome (coluna1 TIPO, coluna2 TIPO, ...). Cada coluna recebe um nome e um tipo opcional, e você pode adicionar constraints como PRIMARY KEY, NOT NULL ou DEFAULT. O comando é executado na hora e a tabela fica gravada no arquivo do banco.
Para que serve o IF NOT EXISTS no CREATE TABLE?
O CREATE TABLE IF NOT EXISTS nome (...) só cria a tabela se ainda não existir uma com aquele nome. Sem isso, rodar o script de novo num banco já existente dispara o erro table already exists. É a proteção padrão para scripts de migração e código de inicialização da aplicação.
Dá para criar uma tabela a partir de um SELECT no SQLite?
Dá sim — CREATE TABLE novo_nome AS SELECT ... monta uma nova tabela a partir do resultado de uma consulta. A tabela nova herda os nomes das colunas e os dados, mas não copia constraints, chaves primárias nem índices da origem. Use para snapshots e tabelas temporárias de trabalho, nunca como substituto de um schema bem definido.
Qual a diferença entre tabela temporária e tabela normal?
O CREATE TEMP TABLE (ou CREATE TEMPORARY TABLE) cria uma tabela que existe apenas durante a conexão atual e some quando a conexão é fechada. Já as tabelas normais ficam persistidas no arquivo do banco. Tabelas temporárias caem bem para guardar resultados intermediários sem sujar o schema.