Menu

SQLite: Importar CSV com .import e --csv (guia prático)

Aprenda a importar arquivos CSV no SQLite usando o comando .import — com cabeçalho, tabela existente, separadores diferentes e os erros mais comuns.

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

Importar CSV é coisa da CLI, não do SQL

Não existe um comando IMPORT no dialeto SQL do SQLite. A importação de CSV é uma funcionalidade do shell de linha de comando sqlite3 — um dot-command chamado .import. Essa é uma virada de chave importante se você vem do LOAD DATA INFILE do MySQL ou do COPY do Postgres: esses rodam no servidor, mas o .import é algo que a ferramenta cliente faz por você, lendo o arquivo e disparando INSERTs por baixo dos panos.

Ou seja, tudo o que vem nesta página assume que você está dentro do shell sqlite3:

sqlite3 mydata.db

Se você precisa importar a partir do código da aplicação — em Python, Node ou Go —, o caminho é ler o CSV na linguagem escolhida e usar INSERT com parâmetros. Esse fluxo fica para o capítulo de integração com aplicações. Aqui o foco é a CLI.

Como importar CSV no SQLite com .import

O caminho mais curto: avise ao SQLite que o arquivo é CSV e depois aponte o .import para o arquivo e o nome da tabela.

.mode csv
.import people.csv people

Duas coisas podem acontecer, dependendo de a tabela people já existir ou não:

  • A tabela não existe — o SQLite cria a tabela usando a primeira linha do CSV como nomes das colunas. Todas as colunas recebem afinidade TEXT.
  • A tabela já existe — o SQLite insere todas as linhas do arquivo como dados. Ou seja, se houver cabeçalho, ele vira uma linha qualquer da tabela.

Esse segundo caso é onde quase todo mundo tropeça na primeira tentativa. Se o seu CSV tem cabeçalho e a tabela já existe, você precisa pular essa linha explicitamente.

Como pular o cabeçalho ao importar CSV em tabela existente no SQLite

Use --skip 1 para dizer ao .import para ignorar as N primeiras linhas:

CREATE TABLE people (
    name TEXT,
    age  INTEGER,
    city TEXT
);

.import --csv --skip 1 people.csv people

--csv é um atalho para .mode csv aplicado só nesse comando, então você não precisa configurar o modo separadamente. O --skip 1 descarta o cabeçalho. As linhas restantes são inseridas em people na ordem das colunas.

Uma conferida rápida depois da importação:

SELECT count(*) FROM people;
SELECT * FROM people LIMIT 5;

A ordem das colunas no arquivo precisa bater com a ordem das colunas na tabela. Não existe nenhum mapeamento por nome de cabeçalho — o .import simplesmente joga o N-ésimo campo do CSV na N-ésima coluna da tabela.

Deixando o SQLite criar a tabela automaticamente

Pra trabalho exploratório, o caminho mais prático é pular o CREATE TABLE e deixar o .import montar a tabela a partir do cabeçalho do CSV:

.mode csv
.import sales.csv sales

.schema sales

.schema sales vai te mostrar algo parecido com:

CREATE TABLE sales(
  "order_id" TEXT,
  "amount" TEXT,
  "ordered_at" TEXT
);

Repare que todas as colunas vieram como TEXT. Isso é proposital — o .import não tenta adivinhar tipos. Se você quer amount como número de verdade e ordered_at como timestamp, crie a tabela antes com os tipos certos e depois rode o import com --skip 1. A afinidade de tipos do SQLite vai converter as strings numéricas em inteiros e reais na hora do insert.

Separadores customizados: TSV, pipe e ponto e vírgula

O .mode csv assume vírgula como separador. Para arquivos separados por tabulação, troque o modo:

.mode tabs
.import data.tsv events

Para usar outros separadores, defina .separator depois de escolher o modo:

.mode csv
.separator "|"
.import pipe_data.txt events

Vale destacar uma coisa: o .mode csv segue as regras de aspas do RFC 4180 — então campos com vírgulas ou quebras de linha embutidas funcionam normalmente, desde que estejam corretamente entre aspas ("). Já o .mode tabs é um modo mais simples, que apenas divide pelo caractere e não trata aspas. Se o seu arquivo tem campos entre aspas com separadores embutidos, mantenha o .mode csv e apenas troque o separador.

Um exemplo prático na vida real

Imagine que o orders.csv esteja assim:

order_id,customer,amount,ordered_at
1001,Ada,49.99,2026-01-12
1002,Boris,12.50,2026-01-13
1003,"Chen, Wei",199.00,2026-01-14

Repare que a linha 3 traz uma vírgula dentro de um campo entre aspas. Veja a sessão completa:

Em um shell real, o bloco INSERT seria substituído por um único .import --csv --skip 1 orders.csv orders. O campo "Chen, Wei" permanece intacto porque o modo CSV respeita as aspas. O amount vira um número de verdade e o order_id um inteiro, graças aos tipos definidos nas colunas.

Envolvendo a importação em uma transação

O .import dispara um INSERT por linha. Para alguns milhares de linhas, tudo bem. Para um milhão, fica dolorosamente lento — a menos que você envolva tudo em uma transação para o SQLite não ficar dando commit a cada linha:

BEGIN;
.import --csv --skip 1 big_file.csv events
COMMIT;

Essa única mudança pode transformar uma importação de vários minutos em poucos segundos. Se algo falhar no meio do caminho, o ROLLBACK desfaz a carga parcial, o que também ajuda bastante em tentativas de repetição.

Dá pra acelerar ainda mais removendo os índices antes da importação e recriando depois — manter índice atualizado linha por linha pesa no tempo total.

Erros comuns ao importar CSV no SQLite e como resolver

Error: expected N columns but found M — o número de campos de uma linha não bate com a tabela. Geralmente é por causa de:

  • Uma vírgula perdida num campo sem aspas. Reexporte o arquivo com aspas no padrão CSV correto, ou troque para .mode csv (RFC 4180) no lugar de .mode tabs.
  • Uma linha em branco no final do arquivo. Edite o arquivo ou use o --skip de forma criativa.
  • A tabela tem mais colunas que o CSV. Aí você adiciona as colunas faltantes no arquivo, ou importa para uma tabela de staging com o formato certo e copia de lá pra tabela final.

Linha de cabeçalho virou dado — você esqueceu o --skip 1 ao importar para uma tabela existente. Apague essa linha (DELETE FROM t WHERE rowid = 1) e rode de novo com a flag.

Números armazenados como texto — você deixou o .import criar a tabela, então toda coluna virou TEXT. Apague a tabela, defina ela manualmente com colunas INTEGER/REAL e reimporte.

Error: no such file — o caminho é relativo ao diretório onde você abriu o sqlite3, não ao arquivo do banco. Use um caminho absoluto ou faça cd para a pasta certa antes de abrir o shell.

A CLI mostra o número da linha quando dá erro, que é a forma mais rápida de achar a linha problemática num arquivo grande.

Resumo rápido

  • .import é um dot-command da CLI, não é SQL. Tem que rodar dentro do shell do sqlite3.
  • Use --csv para tratar aspas corretamente e --skip 1 para ignorar o cabeçalho.
  • Se a tabela não existir, o .import cria a partir do cabeçalho — mas todas as colunas vão ser TEXT. Crie a tabela você mesmo para ter os tipos certos.
  • Envolva importações grandes com BEGIN/COMMIT para evitar uma transação por linha.
  • A ordem das colunas no arquivo precisa bater com a ordem das colunas da tabela.

Próximo passo: exportando os dados de volta

Importar é só metade da história. O mesmo shell consegue exportar resultados de consultas ou tabelas inteiras para CSV, JSON ou SQL — útil para backups, pipelines de dados e para entregar dados a outras ferramentas. É o que vamos ver no próximo tópico, sobre exportação de dados.

Perguntas frequentes

Como importar um arquivo CSV no SQLite?

Abra o banco com a CLI sqlite3, ative o modo CSV com .mode csv e rode .import data.csv nome_da_tabela. Se a tabela ainda não existir, o SQLite cria ela usando a primeira linha do arquivo como nome das colunas. Se ela já existir, todas as linhas do arquivo entram como dados — então normalmente você vai querer usar .import --skip 1 para pular o cabeçalho.

Como importar um CSV com cabeçalho em uma tabela que já existe no SQLite?

Use .import --csv --skip 1 data.csv nome_da_tabela. A flag --skip 1 diz ao SQLite para ignorar a primeira linha, evitando que o cabeçalho vire um registro. Sem ela, você acaba com uma linha contendo os próprios nomes das colunas como se fossem dados.

Por que minha importação de CSV no SQLite falha com 'expected N columns but found M'?

O arquivo tem linhas com uma quantidade de colunas diferente da tabela — geralmente por causa de vírgulas dentro de campos, aspas mal fechadas ou uma linha vazia no final. Use .mode csv (ou --csv) em vez de .mode tabs para que o SQLite trate as aspas conforme o RFC 4180, e abra o arquivo num editor de texto para procurar separadores soltos. A CLI mostra o número da linha problemática, que é o jeito mais rápido de achar o registro com defeito.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR