web-dev-qa-db-ja.com

SQLITE SQLダンプファイルをPOSTGRESQLに変換する

POSTGRESQLで本番環境のSQLITEデータベースを使用して開発を行ってきました。ローカルデータベースを大量のデータで更新し、特定のテーブルを運用データベースに転送する必要がありました。

実行中sqlite database .dump > /the/path/to/sqlite-dumpfile.sql、SQLITEは次の形式でテーブルダンプを出力します。

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;

上記を、実稼働サーバーにインポートできるPOSTGRESQL互換のダンプファイルに変換するにはどうすればよいですか?

85
DevX

そのダンプファイルをpsqlに直接フィードできるはずです。

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

id列を「自動インクリメント」にしたい場合は、テーブル作成行でそのタイプを「int」から「serial」に変更します。 PostgreSQLは、その列にシーケンスを付加して、NULL IDを持つINSERTに次の利用可能な値が自動的に割り当てられるようにします。 PostgreSQLはAUTOINCREMENTコマンドも認識しないため、これらを削除する必要があります。

また、SQLiteスキーマのdatetime列を確認し、PostgreSQLのtimestampに変更することもできます(これを指摘してくれた Clay に感謝します)。

SQLiteにブール値がある場合は、101::boolean0::boolean(それぞれ)を変換するか、ブール列をスキーマの整数に変更できます。ダンプのセクションをインポートしてから、PostgreSQL内で手動で修正します。

SQLiteにBLOBがある場合は、byteaを使用するようにスキーマを調整する必要があります。おそらく、いくつかの decodeの呼び出しも で混在させる必要があります。たくさんのBLOBを処理する場合は、お気に入りの言語で手っ取り早くコピー機を作成する方が、SQLを変更するよりも簡単かもしれません。

いつものように、外部キーがある場合は、おそらく挿入順序の問題を避けるために set constraints all deferred を調べて、コマンドをBEGIN/COMMITペア内に配置する必要があります。

Nicolas Riley に、boolean、blob、constraintsのメモを提供してくれました。

一部のSQLite3クライアントによって生成されたコードに`がある場合、それらを削除する必要があります。

PostGRESQLはunsigned列も認識しないため、削除するか、次のようなカスタムの制約を追加することをお勧めします。

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

SQLiteはnull値をデフォルトで''に設定しますが、PostgreSQLではNULLとして設定する必要があります。

SQLiteダンプファイルの構文は、ほとんどPostgreSQLと互換性があるため、いくつかのパッチを適用してpsqlに入力できます。 SQL INSERTを使用して大量のデータをインポートするには時間がかかる場合がありますが、機能します。

90
mu is too short

pgloader

SQLiteダンプをPostgreSQLに変換する方法を探しているときに、この投稿に出会いました。この投稿には受け入れられた回答がありますが(その+1で良い回答もあります)、これを追加することが重要だと思います。

ここで解決策を検討し始め、より自動化された方法を探していることに気付きました。私はwikiドキュメントを調べました:

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

そしてpgloaderを発見しました。非常にクールなアプリケーションであり、比較的使いやすいです。フラットなSQLiteファイルを使用可能なPostgreSQLデータベースに変換できます。 *.debからインストールし、テストディレクトリに次のようなcommandファイルを作成しました。

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

docs 状態のように。次に、testdbcreatedbを作成しました。

createdb testdb

次のようにpgloaderコマンドを実行しました。

pgloader command

そして、新しいデータベースに接続します:

psql testdb

データを確認するためのいくつかのクエリの後、非常にうまく機能したようです。これらのスクリプトのいずれかを実行しようとした場合、またはここで説明した段階的な変換を実行した場合、もっと多くの時間を費やしていたでしょう。

概念を証明するために、私はこのtestdbをダンプし、運用サーバーの開発環境にインポートし、データを適切に転送しました。

55
nicorellius

sqlite3からpostgresへの移行を行うスクリプトを作成しました。 https://stackoverflow.com/a/4581921/1303625 に記載されているすべてのスキーマ/データ変換を処理するわけではありませんが、必要な処理を実行します。他の人にとって良い出発点になることを願っています。

https://Gist.github.com/2253099

15
Earle Clubb

sequel gem (a Ruby library)は、異なるデータベース間でデータのコピーを提供します: http://sequel.jeremyevans.net/rdoc/files/doc /bin_sequel_rdoc.html#label-Copy+Databases

Sqliteの場合、次のようになります:sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db

11
lulalala

1つのライナーを使用できます。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 
7
develCuy

PostgreSQLが受け入れるようにsqliteダンプを編集/正規表現しようとしましたが、退屈でエラーが発生しやすいです。

私が本当に早く働かせたもの:

最初にデータなしでPostgreSQLでスキーマを再作成します。ダンプを編集するか、ORMを使用している場合は幸運であり、両方のバックエンド(sqlalchemy、peewee、...)と通信します。

次に、パンダを使用してデータを移行します。 boolフィールドを持つテーブルがあると仮定します(sqliteでは0/1ですが、PostgreSQLではt/fでなければなりません)

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)

これはチャームのように機能し、正規表現とは異なり、各関数の作成、読み取り、デバッグが簡単です。

対応するソースキーを使用してテーブルをロードした後に、外部キーを使用してテーブルをロードする必要があるという唯一の注意事項があります。循環依存の場合はありませんでした。その場合は、キーチェックを一時的に中断できると思います。

0
agomcas