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互換のダンプファイルに変換するにはどうすればよいですか?
そのダンプファイルを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にブール値がある場合は、1
と0
と1::boolean
と0::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を使用して大量のデータをインポートするには時間がかかる場合がありますが、機能します。
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 状態のように。次に、testdb
でcreatedb
を作成しました。
createdb testdb
次のようにpgloader
コマンドを実行しました。
pgloader command
そして、新しいデータベースに接続します:
psql testdb
データを確認するためのいくつかのクエリの後、非常にうまく機能したようです。これらのスクリプトのいずれかを実行しようとした場合、またはここで説明した段階的な変換を実行した場合、もっと多くの時間を費やしていたでしょう。
概念を証明するために、私はこのtestdb
をダンプし、運用サーバーの開発環境にインポートし、データを適切に転送しました。
sqlite3
からpostgres
への移行を行うスクリプトを作成しました。 https://stackoverflow.com/a/4581921/1303625 に記載されているすべてのスキーマ/データ変換を処理するわけではありませんが、必要な処理を実行します。他の人にとって良い出発点になることを願っています。
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
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
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)
これはチャームのように機能し、正規表現とは異なり、各関数の作成、読み取り、デバッグが簡単です。
対応するソースキーを使用してテーブルをロードした後に、外部キーを使用してテーブルをロードする必要があるという唯一の注意事項があります。循環依存の場合はありませんでした。その場合は、キーチェックを一時的に中断できると思います。