将SQLITE SQL转储文件转换为POSTGRESQL


96

我一直在使用SQLITE数据库和POSTGRESQL中的生产进行开发。我刚刚用大量数据更新了本地数据库,并且需要将特定的表传输到生产数据库。

基于运行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兼容转储文件?


1
那么,该命令没有工作,为我,直到我改变源码sqlite3的
杰拉勒额尔古纳

Answers:


101

您应该能够将转储文件直接输入psql

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

如果您希望id列为“自动递增”,则在表创建行中将其类型从“ int”更改为“ serial”。PostgreSQL然后将一个序列附加到该列,以便具有NULL ID的INSERT被自动分配给下一个可用值。PostgreSQL也不会识别AUTOINCREMENT命令,因此需要删除这些命令。

您还需要检查datetimeSQLite模式中的列并将其更改timestamp为PostgreSQL(感谢Clay指出这一点)。

如果您的SQLite中有布尔值,则可以将1and 01::booleanand 0::boolean(分别)进行转换,或者可以在转储的schema部分中将boolean列更改为整数,然后在导入后在PostgreSQL中手动对其进行修复。

如果SQLite中有BLOB,则需要调整要使用的架构bytea。您可能还需要混入一些decode电话。如果您要处理大量的BLOB,则用您喜欢的语言编写快速的“脏”复印机可能比处理SQL更容易。

像往常一样,如果您有外键,那么您可能需要调查一下set constraints all deferred以避免插入顺序问题,将命令放在BEGIN / COMMIT对中。

感谢Nicolas Riley提供的布尔值,blob和约束说明。

如果您有`某些SQLite3客户端生成的代码,则需要将其删除。

PostGRESQL也不识别unsigned列,您可能要删除它们,或添加一个定制约束,例如:

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

虽然SQLite默认将null值设置为'',但PostgreSQL要求将它们设置为NULL

SQLite转储文件中的语法似乎与PostgreSQL大部分兼容,因此您可以修补一些内容并将其提供给psql。通过SQL INSERT导入大量数据可能需要一些时间,但它可以工作。


4
不,您想保留交易以避免一些开销。
Peter Eisentraut 2011年

3
这很好。我还要注意,如果需要迁移sqlite datetime列,则必须将其更改timestamp为postgres。
粘土

4
我遇到了其他一些问题:更改BLOBBYTEAstackoverflow.com/questions/3103242),将BOOLEAN列的0/1更改为'0'/'1',并推迟了约束(DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED)。
Nicholas Riley '02

1
@NicholasRiley:谢谢。我把它交给了社区维基,因为它已经变成了集体努力,公平是公平的。
亩太短了

2
您可以在PostgreSQL的使用TO_TIMESTAMP()将时间戳转换为progreSQL时间戳
R03

61

pgloader

我在寻找一种将SQLite转储转换为PostgreSQL的方法时遇到了这篇文章。即使这篇文章的答案是可以接受的(+1也是一个很好的答案),但我认为添加这一点很重要。

我开始在这里研究解决方案,并意识到我正在寻找一种更自动化的方法。我查阅了wiki文档:

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

发现了pgloader。非常酷的应用程序,并且相对易于使用。您可以将平面SQLite文件转换为可用的PostgreSQL数据库。我从安装,*.debcommand在测试目录中创建了这样的文件:

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

文档状态一样。然后我创建了一个testdb具有createdb

createdb testdb

我这样运行pgloader命令:

pgloader command

然后连接到新数据库:

psql testdb

经过一些查询以检查数据后,它似乎运行良好。我知道如果我尝试运行这些脚本之一或执行此处提到的逐步转换,那我将花费更多的时间。

为了证明这一概念,我将其转储testdb并导入到生产服务器上的开发环境中,并很好地传输了数据。


2
注意(仍然受支持)Ubuntu发行版可能已经过时了-v2.xy已被弃用,并且实际上不起作用。v3.2.x可能有效,但建议使用v3.2.3。我已经从最新版本中获取了v3.2.3,并使用sudo dpkg -i <.deb文件名>进行了安装,它对依赖项没有任何问题。
silpol '16

我同意@silpol-确保下载最新的稳定版本并使用您的fav软件包管理器进行安装;对于“命令”文件,这只是一个名为“命令”的文本文件,没有扩展名(即,文件名末尾不需要.txt),您无需将文件名放在尖括号中;我必须更改psql数据库的search_parth才能查看我的数据;pgloader运作良好,为我省去了很多麻烦
BKSpurgeon '16

这救了我的一天。
Yakob Ubaidi

1
是的,当我遇到此问题时,我很挣扎,而该工具使它变得如此简单...有时候事情进展顺利,不是吗?
nicorellius

多谢兄弟。我认为这个答案值得被接受!很好的工具。
mohamed_18 '18


12

续集宝石(一个Ruby库)提供的数据在不同的数据库复制: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

首先安装Ruby,然后通过运行安装gem gem install sequel

如果是sqlite,它将是这样的: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db


1
很棒的解决方案。比摆弄容易得多pgloader
michaeldever

绝对地,pgloader很乱,GC似乎在庞大的数据库上崩溃了:github.com/dimitri/pgloader/issues/962
hasufell

7

您可以使用一个衬板,这是借助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 

LONG类型不能替代,例如
yetanothercoder 2015年

1
可以添加一个项目sed -e 's/DATETIME/TIMESTAMP/g'
silpol

sed -e 's/TINYINT(1)/SMALLINT/g' -有关所有数据类型的比较,请参见stackoverflow.com/questions/1942586/…–
Purplejacket

我也有一个SMALLINT问题,在sqlite中默认为't'或'f'。显然是布尔值,但对两个数据库系统都不熟悉,因此不建议推荐安全修复程序。
迷宫

1
替换' | sed -e '; :)
AstraSerg

0

我已经尝试过编辑/正则表达式sqlite转储,所以PostgreSQL接受它,这很乏味并且容易出错。

我的工作非常迅速:

首先在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)

这就像一个符咒,很容易编写,读取和调试每个函数,与正则表达式不同(对我而言)。

现在,您可以尝试使用PostgreSQL加载生成的csv(甚至使用管理工具以图形方式),唯一的警告是,在使用相应的源密钥加载表之后,必须使用外键加载表。我没有循环依赖的情况,如果是这种情况,我想您可以暂时中止密钥检查。


-1

pgloader在将sqlite中的数据库转换为postgresql方面产生了奇迹。

这是将本地sqlitedb转换为远程PostgreSQL数据库的示例:

pgloader sqlite.db postgresql:// 用户名密码 @ 主机名 / dbname


1
Pgloader非常容易出错,而且不可靠。它立即崩溃并显示错误KABOOM! Control stack exhausted (no more space for function call frames).
Cerin,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.