Converter arquivo de despejo SQLITE SQL em POSTGRESQL

96

Tenho feito desenvolvimento usando banco de dados SQLITE com produção em POSTGRESQL. Acabei de atualizar meu banco de dados local com uma grande quantidade de dados e preciso transferir uma tabela específica para o banco de dados de produção.

Com base na execução sqlite database .dump > /the/path/to/sqlite-dumpfile.sql, o SQLITE gera um despejo de tabela no seguinte formato:

BEGIN TRANSACTION;
CREATE TABLE "courses_school" ("id" integer PRIMARY KEY, "department_count" integer NOT NULL DEFAULT 0, "the_id" integer UNIQUE, "school_name" varchar(150), "slug" varchar(50));
INSERT INTO "courses_school" VALUES(1,168,213,'TEST Name A',NULL);
INSERT INTO "courses_school" VALUES(2,0,656,'TEST Name B',NULL);
....
COMMIT;

Como faço para converter o acima em um arquivo de despejo compatível com POSTGRESQL que posso importar para o meu servidor de produção?

DevX
fonte
1
Bem, esse comando não funcionou para mim até que eu alterei sqlite para sqlite3
Celal Ergün

Respostas:

100

Você deve ser capaz de alimentar esse arquivo de despejo diretamente em psql:

/path/to/psql -d database -U username -W < /the/path/to/sqlite-dumpfile.sql

Se você quiser que a idcoluna tenha um "incremento automático", altere seu tipo de "int" para "serial" na linha de criação da tabela. O PostgreSQL irá então anexar uma sequência àquela coluna para que INSERTs com ids NULL sejam automaticamente atribuídos ao próximo valor disponível. O PostgreSQL também não reconhecerá os AUTOINCREMENTcomandos, portanto, eles precisam ser removidos.

Você também vai querer verificar as datetimecolunas no esquema SQLite e alterá-las timestamppara PostgreSQL (obrigado a Clay por apontar isso).

Se você tiver booleanos em seu SQLite, poderá converter 1e 0e 1::booleane 0::boolean(respectivamente) ou alterar a coluna booleana para um inteiro na seção de esquema do dump e corrigi-los manualmente dentro do PostgreSQL após a importação.

Se você tiver BLOBs em seu SQLite, você desejará ajustar o esquema a ser usado bytea. Provavelmente, você também precisará misturar algumas decodechamadas . Escrever uma copiadora rápida e suja em sua linguagem favorita pode ser mais fácil do que mutilar o SQL se você tiver muitos BLOBs para lidar.

Como de costume, se você tiver chaves estrangeiras, provavelmente desejará set constraints all deferredevitar problemas de ordem de inserção, colocando o comando dentro do par BEGIN / COMMIT.

Agradecimentos a Nicolas Riley pelas notas booleanas, de bolhas e de restrições.

Se você tiver `em seu código, conforme gerado por alguns clientes SQLite3, será necessário removê-los.

PostGRESQL também não reconhece unsignedcolunas, você pode querer descartar isso ou adicionar uma restrição feita sob medida, como esta:

CREATE TABLE tablename (
    ...
    unsigned_column_name integer CHECK (unsigned_column_name > 0)
);

Embora o padrão do SQLite para valores nulos '', o PostgreSQL requer que eles sejam configurados como NULL.

A sintaxe no arquivo de despejo SQLite parece ser compatível com o PostgreSQL, portanto, você pode corrigir algumas coisas e alimentá-lo psql. A importação de uma grande pilha de dados por meio de SQL INSERTs pode demorar um pouco, mas funcionará.

mu é muito curto
fonte
4
Não, você deseja manter a transação para evitar alguma sobrecarga.
Peter Eisentraut
3
Isso funciona muito bem. Eu também observaria que, se você precisar migrar datetimecolunas sqlite , terá que alterá-las timestamppara o postgres.
Clay
4
Mais alguns problemas que encontrei: mudar BLOBpara BYTEA( stackoverflow.com/questions/3103242 ), mudar 0/1 para BOOLEANcolunas para '0' / '1' e adiar restrições ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Nicholas Riley
1
@NicholasRiley: Obrigado por isso. Desisti disso para um wiki da comunidade, já que se tornou um esforço de grupo, justo é justo.
mu é muito curto
2
Você pode usar to_timestamp () no postgreSQL para converter um carimbo de data / hora em um carimbo de data
progreSQL
61

pgloader

Me deparei com este post ao procurar uma maneira de converter um despejo SQLite para PostgreSQL. Mesmo que esta postagem tenha uma resposta aceita (e uma boa resposta com +1), acho que adicionar isso é importante.

Comecei a pesquisar as soluções aqui e percebi que estava procurando um método mais automatizado. Eu pesquisei os documentos wiki:

https://wiki.postgresql.org/wiki/Converting_from_other_Databases_to_PostgreSQL

e descoberto pgloader. Aplicativo muito legal e relativamente fácil de usar. Você pode converter o arquivo plano SQLite em um banco de dados PostgreSQL utilizável. Instalei do *.debe criei um commandarquivo como este em um diretório de teste:

load database  
    from 'db.sqlite3'  
    into postgresql:///testdb 
       
with include drop, create tables, create indexes, reset sequences  
         
set work_mem to '16MB', maintenance_work_mem to '512 MB';

como o estado docs . Então criei um testdbcom createdb:

createdb testdb

Eu executei o pgloadercomando assim:

pgloader command

e então conectado ao novo banco de dados:

psql testdb

Após algumas consultas para verificar os dados, parece que funcionou muito bem. Eu sei que se eu tivesse tentado executar um desses scripts ou fazer a conversão passo a passo mencionada aqui, teria gasto muito mais tempo.

Para provar o conceito, descartei isso testdbe importei para um ambiente de desenvolvimento em um servidor de produção e os dados foram transferidos de forma adequada.

Nicorellius
fonte
2
Esteja ciente de que (ainda com suporte) as distribuições do Ubuntu podem ter uma versão desatualizada - v2.xy já está obsoleta e não funciona. A v3.2.x pode funcionar, mas a v3.2.3 é recomendada. Eu obtive a v3.2.3 do sistema de ponta e instalei com sudo dpkg -i <nome do arquivo .deb> , não tive problemas com dependências.
silpol
Concordo com @silpol - certifique-se de baixar a versão estável mais recente e instalar usando seu gerenciador de pacotes fav; para o arquivo de "comando", este é apenas um arquivo de texto chamado 'comando' sem nome de extensão (ou seja, sem necessidade de .txt no final do nome do arquivo), você não precisa colocar o nome do arquivo entre colchetes angulares; Tive que mudar o search_parth do banco de dados psql para ver meus dados; pgloader funciona bem e me poupou de muitos aborrecimentos
BKSpurgeon
isso salva meu dia.
Yakob Ubaidi
1
Sim, eu estava lutando quando encontrei esse problema, e aquela ferramenta tornou tudo tão fácil ... Às vezes as coisas funcionam bem, não é?
Nicorellius
Obrigado mano. Vejo que essa resposta vale a pena ser aceita! ferramenta muito boa.
mohamed_18
12

A sequência gem (uma biblioteca Ruby) oferece cópia de dados em diferentes bancos de dados: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Primeiro instale o Ruby, depois instale o gem executando gem install sequel.

No caso do sqlite, seria assim: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db

lulalala
fonte
1
Solução incrível. Muito mais fácil do que brincar pgloader.
michaeldever
Com certeza, o pgloader é confuso, o GC parece travar em bancos de dados enormes: github.com/dimitri/pgloader/issues/962
hasufell
7

Você pode usar um liner, aqui está um exemplo com a ajuda do comando sed:

sqlite3 mjsqlite.db .dump | sed -e 's/INTEGER PRIMARY KEY AUTOINCREMENT/SERIAL PRIMARY KEY/' | sed -e 's/PRAGMA foreign_keys=OFF;//' | sed -e 's/unsigned big int/BIGINT/g' | sed -e 's/UNSIGNED BIG INT/BIGINT/g' | sed -e 's/BIG INT/BIGINT/g' | sed -e 's/UNSIGNED INT(10)/BIGINT/' | sed -e 's/BOOLEAN/SMALLINT/g' | sed -e 's/boolean/SMALLINT/g' | sed -e 's/UNSIGNED BIG INT/INTEGER/g' | sed -e 's/INT(3)/INT2/g' | sed -e 's/DATETIME/TIMESTAMP/g' | psql mypqdb mypguser 
develCuy
fonte
não há substituição para o tipo LONG, por exemplo
codificador de
1
mais um item pode ser adicionadosed -e 's/DATETIME/TIMESTAMP/g'
silpol
sed -e 's/TINYINT(1)/SMALLINT/g' - e para uma comparação de todos os tipos de dados, consulte stackoverflow.com/questions/1942586/…
Purplejacket
Eu também tive um problema com um SMALLINT cujo padrão era 't' ou 'f' no sqlite. Obviamente um booleano, mas não está familiarizado o suficiente com nenhum dos sistemas db para recomendar uma correção segura.
labirinto
1
Substitua ' | sed -e 'por ; :)
AstraSerg
0

Eu tentei editar / regexping o dump sqlite para que o PostgreSQL o aceite, é entediante e sujeito a erros.

O que eu tenho que trabalhar muito rápido:

Primeiro, recrie o esquema no PostgreSQL sem quaisquer dados, editando o dump ou se estiver usando um ORM, você pode ter sorte e ele se comunica com os dois back-ends (sqlalchemy, peewee, ...).

Em seguida, migre os dados usando o pandas. Suponha que você tenha uma tabela com um campo bool (que é 0/1 em sqlite, mas deve ser t / f em PostgreSQL)

def int_to_strbool(df, column):
    df = df.replace({column: 0}, 'f')
    df = df.replace({column: 1}, 't')
    return df

#def other_transform(df, column):
#...

conn = sqlite3.connect(db)
df = pd.read_sql(f'select * from {table_name}', conn)

df = int_to_strbool(df, bool_column_name)
#df = other_transform(df, other_column_name)

df.to_csv(table_name + '.csv'), sep=',', header=False, index=False)

Funciona muito bem, é fácil de escrever, ler e depurar cada função, ao contrário (para mim) das expressões regulares.

Agora você pode tentar carregar o csv resultante com PostgreSQL (mesmo graficamente com a ferramenta admin), com a única ressalva de que você deve carregar as tabelas com chaves estrangeiras depois de ter carregado as tabelas com as chaves de origem correspondentes. Eu não tive o caso de uma dependência circular, acho que você pode suspender temporariamente a verificação de chave se for o caso.

agomcas
fonte
-1

O pgloader faz maravilhas na conversão de banco de dados em sqlite para postgresql.

Aqui está um exemplo de conversão de um sqlitedb local em um banco de dados PostgreSQL remoto:

pgloader sqlite.db postgresql: // username : password @ hostname / dbname

Kouichi
fonte
1
O Pgloader tem muitos bugs e não é confiável. Ele trava imediatamente com o erroKABOOM! Control stack exhausted (no more space for function call frames).
Cerin