Converta SQLite para PostgreSQL
Solte um arquivo de banco de dados SQLite (.db, .sqlite, .sqlite3) ou o SQL que o .dump do sqlite3 escreve, e baixe um script do PostgreSQL com as mesmas tabelas, chaves, índices e dados. Cada coluna recebe o tipo em que seus valores cabem, e cada valor que o PostgreSQL não aceita como está aparece no relatório.
18 linhas convertidas, nenhuma correção, nenhuma rejeitada
Tabelas em shop_2024_sqlite.sqlDump do SQLite · gerado por sqlite3 · utf-8
customers8 linhas
7 colunas id bigint not null name text not null email text not null country text not null is_active boolean not null signed_up date created_at timestamp(0) not null orders10 linhas
9 colunas id bigint not null customer_id bigint not null status text not null total numeric(10,2) not null items integer not null ordered_at timestamp(0) not null shipped_at timestamp(0) note text receipt bytea
Não convertidos
- Visão order_totals
- Gatilho orders_shipped
Cada banco de dados escreve estes objetos na sua própria linguagem. Reescreva-os para o PostgreSQL.
-- Written by IntoSQL from a SQLite dump. Load it with: psql -v ON_ERROR_STOP=1 -f <file>
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET synchronous_commit = off;
SET maintenance_work_mem = '512MB';
CREATE TABLE customers (
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name text NOT NULL,
email text NOT NULL,
country text DEFAULT 'US' NOT NULL,
is_active boolean DEFAULT true NOT NULL,
signed_up date,
created_at timestamp(0) DEFAULT LOCALTIMESTAMP NOT NULL,
CONSTRAINT customers_check1 CHECK (char_length(country) = 2)
);
CREATE TABLE orders (
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
customer_id bigint NOT NULL,
status text DEFAULT 'pending' NOT NULL,
total numeric(10,2) NOT NULL,
items integer DEFAULT 1 NOT NULL,
ordered_at timestamp(0) NOT NULL,
shipped_at timestamp(0),
note text,
receipt bytea,
CONSTRAINT orders_check1 CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled'))
);
COPY customers (id, name, email, country, is_active, signed_up, created_at) FROM stdin;
1 Ana Martínez ana@example.com MX t 2023-01-15 2023-01-15 10:24:00
2 Zoë Müller zoe@example.de DE t 2023-02-03 2023-02-03 08:11:42
3 José Peña jose@example.es ES f 2023-03-21 2023-03-21 19:05:17
4 李雷 lilei@example.cn CN t 2023-05-09 2023-05-09 02:40:00
5 Noah O'Brien noah@example.ie IE t \N 2023-06-30 14:00:00
6 Amélie Laurent amelie@example.fr FR t 2024-01-02 2024-01-02 09:30:00
7 Ravi Patel ravi@example.in IN f 2024-02-29 2024-02-29 23:59:59
8 Sofia Rossi 🌻 sofia@example.it IT t 2024-04-12 2024-04-12 12:12:12
\.
COPY orders (id, customer_id, status, total, items, ordered_at, shipped_at, note, receipt) FROM stdin;
1 1 shipped 129.9 3 2024-03-01 10:00:00 2024-03-02 16:30:00 \N \N
2 2 paid 54 1 2024-03-02 11:15:00 \N Gift wrap 🎁 \N
3 1 cancelled 12.5 1 2024-03-03 09:45:00 \N Customer changed their mind \N
4 4 shipped 980 12 2024-03-05 02:10:00 2024-03-07 08:00:00 请小心轻放 \\x25504446
5 5 pending 45.75 2 2024-03-08 17:20:00 \N Leave at the door;\nring twice \N
6 6 shipped 310.4 5 2024-03-10 13:00:00 2024-03-11 09:00:00 Fragile: "glass" \N
7 8 paid 76.2 2 2024-03-11 18:45:00 \N \N \N
8 2 paid 19.99 1 2024-03-12 08:00:00 \N Paid at the counter \N
9 3 shipped 64 2 2024-03-14 15:30:00 \N Shipping date never recorded \N
10 7 paid 1499 1 2024-03-15 21:05:00 \N C:\\Users\\ravi\\invoice.pdf \N
\.
-- Keys, indexes and constraints, after the rows so each builds once.
CREATE UNIQUE INDEX customers_pkey ON customers (id);
CREATE UNIQUE INDEX customers_email ON customers (email);
CREATE UNIQUE INDEX orders_pkey ON orders (id);
CREATE INDEX orders_idx_orders_customer ON orders (customer_id);
CREATE INDEX orders_idx_orders_status_date ON orders (status, ordered_at);
ALTER TABLE customers ADD CONSTRAINT customers_pkey PRIMARY KEY USING INDEX customers_pkey;
ALTER TABLE customers ADD CONSTRAINT customers_email UNIQUE USING INDEX customers_email;
ALTER TABLE orders ADD CONSTRAINT orders_pkey PRIMARY KEY USING INDEX orders_pkey;
ALTER TABLE orders ADD CONSTRAINT orders_fkey FOREIGN KEY (customer_id) REFERENCES customers (id) ON DELETE CASCADE NOT VALID;
DO $f$ BEGIN
ALTER TABLE orders VALIDATE CONSTRAINT orders_fkey;
EXCEPTION WHEN foreign_key_violation THEN
RAISE WARNING 'foreign key % has rows without a parent: it stays NOT VALID, and new rows are checked', 'orders_fkey';
END $f$;
SELECT setval(pg_get_serial_sequence('customers', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM customers)::numeric, 0) + 1, 9), 9223372036854775807)::bigint, false);
SELECT setval(pg_get_serial_sequence('orders', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM orders)::numeric, 0) + 1, 11), 9223372036854775807)::bigint, false);
Correções
Nada precisou de correção.
Para revisar
- 1 coluna de texto compara sem diferenciar maiúsculas na origem; o PostgreSQL compara de forma exata, então chaves únicas e buscas podem se comportar de outro jeito. Use uma collation ou um tipo de coluna sem diferenciação de maiúsculas nas colunas que precisarem.
- 2 visões, gatilhos, rotinas ou eventos não foram convertidos; o relatório lista cada um. Recrie-os manualmente no PostgreSQL.
Seu arquivo é convertido neste computador e nunca é enviado.
Outros exemplos:
O que muda do SQLite para o PostgreSQL
Cada linha é uma regra que o conversor aplica, com a linha do relatório que ele escreve quando a regra muda algo nos seus dados.
declared types (any text: VARCHAR(255), DATETIME, BOOLEAN, JSON or none)
o tipo em que cabem todos os valores da coluna
O SQLite guarda qualquer valor em qualquer coluna, então o tipo declarado é uma dica: cada coluna recebe o tipo em que cabem todos os seus valores, e uma coluna com valores misturados mantém o texto deles.
BOOLEAN, BOOL
boolean
Quando todo valor é 0 ou 1; uma coluna que também tem outros valores os mantém como números ou texto.
TEXT, VARCHAR(n), CHAR(n), CLOB
varchar(n) quando todo valor cabe no tamanho declarado, senão text
O SQLite nunca impõe um tamanho; um tamanho declarado só vale quando todo valor cabe nele.
DECIMAL(p,s), NUMERIC
o tipo exato quando todo valor cabe nele, senão um double
O SQLite os guarda como inteiros ou doubles; uma precisão declarada só vale quando os valores cabem nela.
BLOB, and columns holding bytes
bytea
Bytes continuam bytes; texto e números na mesma coluna são mantidos como seus bytes.
DATE, DATETIME, TIMESTAMP holding ISO 8601 text
date, timestamp
Quando todo valor é uma data ou uma data e hora; números epoch e outros textos mantêm seus valores como estão.
JSON holding JSON text
jsonb
Quando todo valor é um objeto ou array JSON.
Infinity in REAL columns
Infinity, como o double do PostgreSQL o guarda
Os doubles do PostgreSQL comportam o infinito.
INTEGER PRIMARY KEY, AUTOINCREMENT
GENERATED BY DEFAULT AS IDENTITY, continuando depois do maior id ou do valor de sqlite_sequence
Só uma coluna declarada exatamente como INTEGER PRIMARY KEY é o rowid; cada linha mantém seu id, e o contador começa depois do maior id já atribuído.
COLLATE NOCASE
comparação exata
O PostgreSQL compara texto de forma exata, a menos que se indique outra coisa; colunas NOCASE deixam de ignorar maiúsculas.
Linha do relatório: case_insensitive_collation
generated columns
STORED
O PostgreSQL 13 a 17 só armazena colunas geradas; a fórmula é a mesma.
Linha do relatório: virtual_as_stored
generated columns with functions IntoSQL doesn't write, and the || operator
uma coluna simples
Uma fórmula que não pode ser escrita deixa uma coluna simples e uma linha no relatório; o dump não tem valores para colunas geradas.
Linha do relatório: generated_not_translated
defaults with functions IntoSQL doesn't write (strftime, randomblob)
sem valor padrão
Um valor padrão que não pode ser escrito fica de fora e é informado; CURRENT_TIMESTAMP e datetime('now') são escritos.
Linha do relatório: default_not_translated
CHECK constraints
traduzidos
Os mesmos CHECKs, testados à medida que cada linha carrega.
CHECK constraints with functions IntoSQL doesn't write
não criado
Um CHECK que não pode ser escrito fica de fora e é informado.
Linha do relatório: check_skipped
partial and expression indexes
não criado
O IntoSQL escreve índices sobre colunas inteiras; crie os outros de novo depois da carga.
Linha do relatório: index_skipped
foreign keys (unenforced unless PRAGMA foreign_keys=ON)
chaves estrangeiras, NOT VALID e depois validadas
O SQLite só verifica chaves estrangeiras quando instruído, então linhas sem pai são comuns: elas carregam, e a chave fica sem verificação com um aviso, em vez de parar a carga.
foreign keys to tables the dump doesn't create
não criada
Uma chave não pode apontar para uma tabela que não existe.
Linha do relatório: foreign_key_skipped
primary keys holding NULL, and NOT NULL columns with values that become NULL
NOT NULL removido
O SQLite deixa uma chave primária que não seja o rowid conter NULL; a coluna não pode ser NOT NULL no destino, senão a carga pararia.
Linha do relatório: not_null_relaxed
views, triggers and virtual tables (FTS, R*Tree)
listados no relatório
O código deles é escrito na linguagem própria do SQLite, e tabelas virtuais precisam dos módulos do SQLite; eles são listados para você recriar. As tabelas internas deles não são copiadas.
Linha do relatório: not_converted_objects
dumps without CREATE TABLE (--data-only)
tipos lidos dos valores
Um dump só de dados tem apenas linhas, então os tipos vêm dos valores e as colunas são numeradas.
Linha do relatório: no_schema
expressions in INSERT values other than the text functions dumps write
NULL
unistr(), replace(), char() e || são avaliados como o shell os escreve; as outras expressões não podem ser avaliadas sem um banco de dados.
Linha do relatório: expression_value
NUL characters in text
removido
O shell sqlite3 e o Python cortam o texto em um caractere NUL ao gerar o dump, então só o que vem antes dele está no dump. O texto do PostgreSQL também não pode contê-lo.
Linha do relatório: nul_removed
text that isn't valid UTF-8
os bytes inválidos como o caractere de substituição
Os dumps escrevem esse texto como bytes brutos; o script é UTF-8.
Linha do relatório: invalid_utf8_replaced
text decoded twice (ñ)
copiado como está
O dump contém exatamente esses caracteres, então eles são copiados; o relatório os aponta.
Linha do relatório: mojibake_suspected
| No SQLite | No PostgreSQL | Linha do relatório |
|---|---|---|
| declared types (any text: VARCHAR(255), DATETIME, BOOLEAN, JSON or none) | o tipo em que cabem todos os valores da colunaO SQLite guarda qualquer valor em qualquer coluna, então o tipo declarado é uma dica: cada coluna recebe o tipo em que cabem todos os seus valores, e uma coluna com valores misturados mantém o texto deles. | |
| BOOLEAN, BOOL | booleanQuando todo valor é 0 ou 1; uma coluna que também tem outros valores os mantém como números ou texto. | |
| TEXT, VARCHAR(n), CHAR(n), CLOB | varchar(n) quando todo valor cabe no tamanho declarado, senão textO SQLite nunca impõe um tamanho; um tamanho declarado só vale quando todo valor cabe nele. | |
| DECIMAL(p,s), NUMERIC | o tipo exato quando todo valor cabe nele, senão um doubleO SQLite os guarda como inteiros ou doubles; uma precisão declarada só vale quando os valores cabem nela. | |
| BLOB, and columns holding bytes | byteaBytes continuam bytes; texto e números na mesma coluna são mantidos como seus bytes. | |
| DATE, DATETIME, TIMESTAMP holding ISO 8601 text | date, timestampQuando todo valor é uma data ou uma data e hora; números epoch e outros textos mantêm seus valores como estão. | |
| JSON holding JSON text | jsonbQuando todo valor é um objeto ou array JSON. | |
| Infinity in REAL columns | Infinity, como o double do PostgreSQL o guardaOs doubles do PostgreSQL comportam o infinito. | |
| INTEGER PRIMARY KEY, AUTOINCREMENT | GENERATED BY DEFAULT AS IDENTITY, continuando depois do maior id ou do valor de sqlite_sequenceSó uma coluna declarada exatamente como INTEGER PRIMARY KEY é o rowid; cada linha mantém seu id, e o contador começa depois do maior id já atribuído. | |
| COLLATE NOCASE | comparação exataO PostgreSQL compara texto de forma exata, a menos que se indique outra coisa; colunas NOCASE deixam de ignorar maiúsculas. | case_insensitive_collation |
| generated columns | STOREDO PostgreSQL 13 a 17 só armazena colunas geradas; a fórmula é a mesma. | virtual_as_stored |
| generated columns with functions IntoSQL doesn't write, and the || operator | uma coluna simplesUma fórmula que não pode ser escrita deixa uma coluna simples e uma linha no relatório; o dump não tem valores para colunas geradas. | generated_not_translated |
| defaults with functions IntoSQL doesn't write (strftime, randomblob) | sem valor padrãoUm valor padrão que não pode ser escrito fica de fora e é informado; CURRENT_TIMESTAMP e datetime('now') são escritos. | default_not_translated |
| CHECK constraints | traduzidosOs mesmos CHECKs, testados à medida que cada linha carrega. | |
| CHECK constraints with functions IntoSQL doesn't write | não criadoUm CHECK que não pode ser escrito fica de fora e é informado. | check_skipped |
| partial and expression indexes | não criadoO IntoSQL escreve índices sobre colunas inteiras; crie os outros de novo depois da carga. | index_skipped |
| foreign keys (unenforced unless PRAGMA foreign_keys=ON) | chaves estrangeiras, NOT VALID e depois validadasO SQLite só verifica chaves estrangeiras quando instruído, então linhas sem pai são comuns: elas carregam, e a chave fica sem verificação com um aviso, em vez de parar a carga. | |
| foreign keys to tables the dump doesn't create | não criadaUma chave não pode apontar para uma tabela que não existe. | foreign_key_skipped |
| primary keys holding NULL, and NOT NULL columns with values that become NULL | NOT NULL removidoO SQLite deixa uma chave primária que não seja o rowid conter NULL; a coluna não pode ser NOT NULL no destino, senão a carga pararia. | not_null_relaxed |
| views, triggers and virtual tables (FTS, R*Tree) | listados no relatórioO código deles é escrito na linguagem própria do SQLite, e tabelas virtuais precisam dos módulos do SQLite; eles são listados para você recriar. As tabelas internas deles não são copiadas. | not_converted_objects |
| dumps without CREATE TABLE (--data-only) | tipos lidos dos valoresUm dump só de dados tem apenas linhas, então os tipos vêm dos valores e as colunas são numeradas. | no_schema |
| expressions in INSERT values other than the text functions dumps write | NULLunistr(), replace(), char() e || são avaliados como o shell os escreve; as outras expressões não podem ser avaliadas sem um banco de dados. | expression_value |
| NUL characters in text | removidoO shell sqlite3 e o Python cortam o texto em um caractere NUL ao gerar o dump, então só o que vem antes dele está no dump. O texto do PostgreSQL também não pode contê-lo. | nul_removed |
| text that isn't valid UTF-8 | os bytes inválidos como o caractere de substituiçãoOs dumps escrevem esse texto como bytes brutos; o script é UTF-8. | invalid_utf8_replaced |
| text decoded twice (ñ) | copiado como estáO dump contém exatamente esses caracteres, então eles são copiados; o relatório os aponta. | mojibake_suspected |
Carregue o script no PostgreSQL
O script cria as tabelas, copia as linhas e depois adiciona chaves, índices e chaves estrangeiras, então carrega rápido e para no primeiro erro.
psql -v ON_ERROR_STOP=1 -d mydb -f sqlite.postgresql.sqlAs chaves estrangeiras são adicionadas como NOT VALID e depois validadas. Se uma linha aponta para uma linha que não existe, o script informa qual restrição, em vez de falhar no meio do caminho.
Para um dump grande, crie o banco de dados antes e execute o script com o psql na mesma máquina do servidor.
O IntoSQL Pro carrega o arquivo direto no PostgreSQL pelo app para desktop ou pela linha de comando, sem escrever um script.
Gere o dump do SQLite para o melhor resultado
O conversor lê o que o dump contém. Estas opções mantêm mais dos seus dados nele:
- O próprio arquivo do banco é convertido como está, lido página por página no navegador. Feche antes o app que escreve nele, para que nenhuma mudança fique para trás no arquivo -wal.
- sqlite3 app.db .dump > app.sql escreve o mesmo banco de dados como SQL, que também é convertido, em .sql ou .sql.gz.
- O DB Browser for SQLite escreve esse SQL com File, Export, Database to SQL file, e o iterdump() do Python também.
O que não é convertido
Visões e gatilhos são escritos na linguagem própria do SQLite. Eles aparecem no relatório pelo nome, nunca são descartados em silêncio, para que você possa reescrevê-los para o PostgreSQL. Tabelas virtuais, como FTS5 e R*Tree, também aparecem, e suas tabelas internas ficam de fora.
Perguntas sobre SQLite para PostgreSQL
Não encontrou a resposta? Escreva para nós pela página de contato e uma pessoa responde. Página de contato
Meu dump é enviado?
Não. O conversor roda no seu navegador e lê o dump do seu disco em partes, então ele nunca sai do seu computador. O app para desktop e a linha de comando também convertem no seu computador.
Qual o tamanho máximo do dump?
O conversor nunca guarda o dump inteiro na memória: ele lê o arquivo duas vezes, por intervalos, e escreve o script à medida que avança. Dumps de vários gigabytes são convertidos no navegador, no app para desktop e com a linha de comando.
Posso converter o próprio arquivo .db?
Sim. Solte o arquivo .db, .sqlite ou .sqlite3: ele é lido no navegador e nunca é enviado. Textos com caracteres NUL e todos os dígitos de um double chegam como foram armazenados, algo que um .dump pode cortar.
De quais versões do SQLite o dump pode vir?
Arquivos de banco de dados do SQLite 3.0 em diante, em UTF-8 ou UTF-16, e dumps do .dump do shell sqlite3 ou do iterdump() do Python. Cada arquivo e dump de teste vem do sqlite3 3.31 a 3.54, incluindo tabelas STRICT e WITHOUT ROWID, e é comparado com a origem célula por célula.
Como os tipos de coluna são decididos quando o SQLite não os impõe?
O tipo declarado é uma dica e os valores decidem: uma coluna vira integer, numeric, double precision, date, timestamp, boolean, bytea ou text quando todo valor cabe nele. Uma coluna com valores misturados mantém o texto deles, e o relatório diz quais.
INTEGER PRIMARY KEY e AUTOINCREMENT são mantidos?
Sim. Uma INTEGER PRIMARY KEY vira uma coluna identity, cada linha mantém seu id, e o próximo id continua depois do maior, ou depois do valor de sqlite_sequence com AUTOINCREMENT.
E as visões e os gatilhos?
Eles aparecem no relatório pelo nome e não são convertidos, porque cada banco de dados os escreve na sua própria linguagem.
Em quais versões do PostgreSQL o script carrega?
PostgreSQL 13 a 18. O mesmo script carrega em cada uma delas e para no primeiro erro se algo der errado.