Ubah file dump SQLITE SQL menjadi POSTGRESQL

97

Saya telah melakukan pengembangan menggunakan database SQLITE dengan produksi di POSTGRESQL. Saya baru saja memperbarui database lokal saya dengan sejumlah besar data dan perlu mentransfer tabel tertentu ke database produksi.

Berdasarkan berjalan sqlite database .dump > /the/path/to/sqlite-dumpfile.sql, SQLITE mengeluarkan tabel dump dalam format berikut:

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;

Bagaimana cara mengonversi yang di atas menjadi file dump yang kompatibel dengan POSTGRESQL yang dapat saya impor ke server produksi saya?

DevX
sumber
1
Nah, perintah itu tidak berfungsi untuk saya sampai saya mengubah sqlite menjadi sqlite3
Celal Ergün

Jawaban:

103

Anda harus dapat memasukkan file dump itu langsung ke psql:

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

Jika Anda ingin idkolom menjadi "auto increment" maka ubah jenisnya dari "int" menjadi "serial" di baris pembuatan tabel. PostgreSQL kemudian akan melampirkan urutan ke kolom itu sehingga INSERT dengan id NULL akan secara otomatis diberikan nilai berikutnya yang tersedia. PostgreSQL juga tidak akan mengenali AUTOINCREMENTperintah, jadi ini perlu dihapus.

Anda juga ingin memeriksa datetimekolom dalam skema SQLite dan mengubahnya menjadi timestampuntuk PostgreSQL. (Terima kasih kepada Clay karena telah menunjukkan hal ini.)

Jika Anda memiliki boolean di SQLite, Anda dapat mengonversi 1dan 0menjadi 1::booleandan 0::boolean(masing-masing) atau Anda dapat mengubah kolom boolean menjadi integer di bagian skema dump dan kemudian memperbaikinya secara manual di dalam PostgreSQL setelah impor.

Jika Anda memiliki BLOB di SQLite Anda, maka Anda harus menyesuaikan skema yang akan digunakan bytea. Anda mungkin perlu menggabungkan beberapa decodepanggilan juga . Menulis mesin fotokopi quick'n'dirty dalam bahasa favorit Anda mungkin lebih mudah daripada merusak SQL jika Anda memiliki banyak BLOB yang harus ditangani.

Seperti biasa, jika Anda memiliki kunci asing maka Anda mungkin ingin melihat ke dalam set constraints all deferreduntuk menghindari memasukkan masalah pengurutan, menempatkan perintah di dalam pasangan BEGIN / COMMIT.

Terima kasih kepada Nicolas Riley untuk boolean, blob, dan catatan kendala.

Jika Anda memiliki `kode Anda, seperti yang dibuat oleh beberapa klien SQLite3, Anda harus menghapusnya.

PostGRESQL juga tidak mengenali unsignedkolom, jadi Anda mungkin ingin menghapusnya atau menambahkan batasan yang dibuat khusus seperti ini:

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

Meskipun SQLite secara default ''menetapkan nilai null menjadi , PostgreSQL mengharuskannya disetel sebagai NULL.

Sintaks dalam file dump SQLite tampaknya sebagian besar kompatibel dengan PostgreSQL sehingga Anda dapat menambal beberapa hal dan memasukkannya ke dalamnya psql. Mengimpor tumpukan besar data melalui SQL INSERT mungkin membutuhkan waktu beberapa saat tetapi itu akan berhasil.

mu terlalu pendek
sumber
4
Tidak, Anda ingin menyimpan transaksi untuk menghindari biaya tambahan.
Peter Eisentraut
3
Ini bekerja dengan baik. Saya juga akan mencatat bahwa jika Anda perlu memigrasi datetimekolom sqlite , Anda harus mengubahnya menjadi timestampuntuk postgres.
Clay
4
Beberapa masalah lagi yang saya hadapi: mengubah BLOBmenjadi BYTEA( stackoverflow.com/questions/3103242 ), mengubah 0/1 untuk BOOLEANkolom menjadi '0' / '1', dan menunda batasan ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Nicholas Riley
1
@NicholasRiley: Terima kasih untuk itu. Saya menyerahkan ini kepada wiki komunitas karena telah berubah menjadi upaya kelompok, adil itu adil.
mu terlalu pendek
2
Anda dapat menggunakan to_timestamp () di postgreSQL untuk mengonversi stempel waktu menjadi stempel waktu progreSQL
r03
62

pgloader

Saya menemukan posting ini ketika mencari cara untuk mengubah dump SQLite menjadi PostgreSQL. Meskipun postingan ini memiliki jawaban yang diterima (dan jawaban yang bagus di +1 itu), saya pikir menambahkan ini penting.

Saya mulai mencari solusi di sini dan menyadari bahwa saya sedang mencari metode yang lebih otomatis. Saya mencari dokumen wiki:

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

dan ditemukan pgloader. Aplikasi yang cukup keren dan relatif mudah digunakan. Anda dapat mengonversi file SQLite datar menjadi database PostgreSQL yang dapat digunakan. Saya menginstal dari *.debdan membuat commandfile seperti ini di direktori pengujian:

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';

seperti negara bagian dokumen . Saya kemudian membuat testdbdengan createdb:

createdb testdb

Saya menjalankan pgloaderperintah seperti ini:

pgloader command

lalu terhubung ke database baru:

psql testdb

Setelah beberapa pertanyaan untuk memeriksa data, tampaknya itu bekerja dengan cukup baik. Saya tahu jika saya mencoba menjalankan salah satu skrip ini atau melakukan konversi bertahap yang disebutkan di sini, saya akan menghabiskan lebih banyak waktu.

Untuk membuktikan konsepnya, saya membuang ini testdbdan mengimpornya ke dalam lingkungan pengembangan di server produksi dan data ditransfer dengan baik.

nicorellius.dll
sumber
2
Berhati-hatilah karena (masih didukung) distribusi Ubuntu mungkin memiliki versi yang sudah ketinggalan zaman - v2.xy sudah usang dan tidak benar-benar berfungsi. v3.2.x mungkin berfungsi tetapi v3.2.3 direkomendasikan. Saya telah mengambil v3.2.3 dari tepi berdarah dan menginstal dengan sudo dpkg -i <.deb file name> , tidak ada masalah dengan dependensi.
silpol
Saya setuju dengan @silpol - pastikan untuk mengunduh rilis stabil terbaru dan instal menggunakan pengelola paket fav Anda; untuk file "perintah" ini hanya file teks yang disebut 'perintah' tanpa nama ekstensi (yaitu tidak perlu .txt di akhir nama file) Anda tidak perlu memasukkan nama file dalam tanda kurung siku; saya harus mengubah search_parth dari database psql untuk melihat data saya; pgloader bekerja dengan baik dan menyelamatkan saya dari kerumitan besar
BKSpurgeon
ini menyelamatkan hariku.
Yakob Ubaidi
1
Ya, saya sedang berjuang ketika saya mengalami masalah ini, dan alat itu membuatnya sangat mudah ... Terkadang semuanya berjalan dengan baik, bukan?
nicorellius
Makasih bro. Saya melihat jawaban ini layak untuk menjadi jawaban yang diterima! alat yang sangat bagus.
mohamed_18
14

The sekuel permata (perpustakaan Ruby) menawarkan data menyalin seluruh database yang berbeda: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Pertama instal Ruby, lalu instal gem dengan menjalankan gem install sequel.

Dalam kasus sqlite, akan seperti ini: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db

lulalala
sumber
1
Solusi luar biasa. Jauh lebih mudah daripada mengotak-atik pgloader.
michaeldever
Benar-benar, pgloader berantakan, GC tampaknya macet pada basis data besar: github.com/dimitri/pgloader/issues/962
hasufell
Jangan ragu untuk memposting jawaban Anda di stackoverflow.com/questions/6148421/… di mana saya menyalin jawaban Anda. Kemudian ping saya dan saya akan mencabut jawaban saya jika Anda menginginkan repetisi untuk itu.
Felix
@Felix terima kasih! Anda dapat mengambil kredit. Bisakah Anda menukar urutan referensi DB (karena menginginkan PG ke SQLite), oh dan menambahkan satu lagi "la" ke id saya. Jawabannya mungkin juga kurang membantu karena mengharuskan mereka menginstal PG pada mesin dev, dan pada saat itu mereka hanya akan menggunakan PG untuk pengembangan.
lulalala
@lulalala Terima kasih. Lakukan itu. Tapi tentang alasannya saya tidak setuju. Misalnya, mereka dapat mengonversi db pada mesin linux dan kemudian menyalinnya ke mesin dev (sebagai file db sqlite). Tapi bagaimanapun semuanya itu ide yang buruk :) Tapi sekuel menyelamatkan pantat saya di sini dalam situasi yang buruk.
Felix
7

Anda dapat menggunakan satu liner, berikut adalah contoh dengan bantuan perintah 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
sumber
tidak ada pengganti untuk tipe PANJANG, misalnya
yetanothercoder
1
satu item lagi dapat ditambahkansed -e 's/DATETIME/TIMESTAMP/g'
silpol
sed -e 's/TINYINT(1)/SMALLINT/g' - dan untuk perbandingan semua tipe data, lihat stackoverflow.com/questions/1942586/…
Purplejacket
Saya juga punya masalah dengan SMALLINT yang defaultnya ke 't' atau 'f' di sqlite. Jelas boolean, tetapi tidak cukup familiar dengan sistem db untuk merekomendasikan perbaikan yang aman.
labirin
1
Ganti ' | sed -e 'dengan ; :)
AstraSerg
0

Saya telah mencoba mengedit / regexping sqlite dump sehingga PostgreSQL menerimanya, itu membosankan dan rawan kesalahan.

Apa yang saya dapatkan untuk bekerja sangat cepat:

Pertama buat ulang skema di PostgreSQL tanpa data apa pun, baik mengedit dump atau jika Anda menggunakan ORM, Anda mungkin beruntung dan itu berbicara ke kedua ujung belakang (sqlalchemy, peewee, ...).

Kemudian migrasikan data menggunakan panda. Misalkan Anda memiliki tabel dengan bidang bool (yaitu 0/1 di sqlite, tetapi harus t / f di 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)

Ini bekerja seperti pesona, mudah untuk menulis, membaca, dan men-debug setiap fungsi, tidak seperti ekspresi reguler (bagi saya).

Sekarang Anda dapat mencoba memuat csv yang dihasilkan dengan PostgreSQL (bahkan secara grafis dengan alat admin), dengan satu-satunya peringatan bahwa Anda harus memuat tabel dengan kunci asing setelah Anda memuat tabel dengan kunci sumber yang sesuai. Saya tidak memiliki kasus ketergantungan melingkar, saya kira Anda dapat menangguhkan sementara pemeriksaan kunci jika itu masalahnya.

agomcas
sumber
-2

pgloader bekerja dengan sangat baik dalam mengonversi database di sqlite ke postgresql.

Berikut adalah contoh untuk mengonversi sqlitedb lokal ke db PostgreSQL jarak jauh:

pgloader sqlite.db postgresql: // nama pengguna : kata sandi @ nama host / nama db

kouichi
sumber
1
Pgloader sangat bermasalah dan tidak dapat diandalkan. Itu segera crash dengan kesalahanKABOOM! Control stack exhausted (no more space for function call frames).
Cerin