Pular para o conteúdo
Início do IntoSQL

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.

Seu arquivo
sqlshop_2024_sqlite.sqlArquivo de exemplo, 3,4 kB
Seu banco de dados

18 linhas convertidas, nenhuma correção, nenhuma rejeitada

Mostrar

Tabelas em shop_2024_sqlite.sqlDump do SQLite · gerado por sqlite3 · utf-8

  • customers8 linhas
    7 colunas
    idbigint not null
    nametext not null
    emailtext not null
    countrytext not null
    is_activeboolean not null
    signed_update
    created_attimestamp(0) not null
  • orders10 linhas
    9 colunas
    idbigint not null
    customer_idbigint not null
    statustext not null
    totalnumeric(10,2) not null
    itemsinteger not null
    ordered_attimestamp(0) not null
    shipped_attimestamp(0)
    notetext
    receiptbytea

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 SQLiteNo PostgreSQLLinha 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, BOOLbooleanQuando 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), CLOBvarchar(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), NUMERICo 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 bytesbyteaBytes continuam bytes; texto e números na mesma coluna são mantidos como seus bytes.
DATE, DATETIME, TIMESTAMP holding ISO 8601 textdate, 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 textjsonbQuando todo valor é um objeto ou array JSON.
Infinity in REAL columnsInfinity, como o double do PostgreSQL o guardaOs doubles do PostgreSQL comportam o infinito.
INTEGER PRIMARY KEY, AUTOINCREMENTGENERATED 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 NOCASEcomparaçã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 columnsSTOREDO 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 || operatoruma 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 constraintstraduzidosOs mesmos CHECKs, testados à medida que cada linha carrega.
CHECK constraints with functions IntoSQL doesn't writenão criadoUm CHECK que não pode ser escrito fica de fora e é informado.check_skipped
partial and expression indexesnã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 createnã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 NULLNOT 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 writeNULLunistr(), 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 textremovidoO 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-8os 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.sql

As 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.