Python从mysql迁移到postgres - fk约束没有丢弃

时间:2017-03-05 10:31:53

标签: python mysql postgresql sqlalchemy database-migration

我正在运行一个带有sqlalchemy的python脚本来导出,然后每天将数据从生产导入到postgres数据库中。该脚本成功运行一次,然后第二次超出脚本失败。正如您将在下面的脚本中看到的,返回的错误表明表中的依赖项(外键)是导致导入失败的原因,但是,我不明白为什么abstract class parent { private config; public function __construct() { $this->config = "get file"; } public function getConfig(){ return $this->config; } } class a extends parent { private config; public function __construct(){ $this->config = parent::getConfig(); } } 对象不会绕过此问题。我选择删除任何初始代码,如repoistory导入,db连接对象,以简化帖子并减少混乱。

sorted_tables

如果在导入数据之前删除整个def create_db(src,dst,src_schema,dst_schema,drop_dst_schema=False): if drop_dst_schema: post_db.engine.execute('DROP SCHEMA IF EXISTS {0} CASCADE'.format(dst_schema)) print "Schema {0} Dropped".format(dst_schema) post_db.engine.execute('CREATE SCHEMA IF NOT EXISTS {0}'.format(dst_schema)) post_db.engine.execute('GRANT USAGE ON SCHEMA {0} TO {0}_ro'.format(dst_schema)) post_db.engine.execute('GRANT USAGE ON SCHEMA {0} TO {0}_rw'.format(dst_schema)) print "Schema {0} Created".format(dst_schema) def create_table(tbl, dst_schema): dest_table=tbl dest_table.schema=dst_schema for col in dest_table.columns: if hasattr(col.type, 'collation'): col.type.collation = None if col.name == 'id': dest_table.append_constraint(PrimaryKeyConstraint(col)) col.type=convert(col.type) timestamp_col=Column ('timestamp',DateTime(timezone=False), server_default=func.now()) #print tbl.c dest_table.append_column(timestamp_col) dest_table.create(post_db.engine,checkfirst=True) post_db.engine.execute('GRANT INSERT ON {1} to {0}_ro'.format(dst_schema, dest_table)) post_db.engine.execute('GRANT ALL PRIVILEGES ON {1} to {0}_rw'.format(dst_schema, dest_table)) print "Table {0} created".format(dest_table) create_db(mysql_db.engine,post_db.engine,src_schema,dst_schema,drop_dst_schema=False) mysql_meta=MetaData(bind=mysql_db.engine) mysql_meta.reflect(schema=src_schema) post_meta=MetaData(bind=post_db.engine) post_meta.reflect(schema=dst_schema) script_begin=time.time() rejected_list=[] for table in mysql_meta.sorted_tables: df=mysql_db.sql_retrieve('select * from {0}'.format(table.name)) df=df.where((pd.notnull(df)), None) print "Table {0} : {1}".format(table.name,len(df)) dest_table=table dest_table.schema = dst_schema dest_table.drop(post_db.engine, checkfirst=True) create_table(dest_table, dst_schema) print "Table {0} emptied".format(dest_table.name) try: start=time.time() if len(df)>10000: for g,df_new in df.groupby(np.arange(len(df))//10000): dict_items=df_new.to_dict(orient='records') post_db.engine.connect().execute(dest_table.insert().values(dict_items)) else: dict_items=df.to_dict(orient='records') post_db.engine.connect().execute(dest_table.insert().values(dict_items)) loadtime=time.time()-start print "Data loaded with datasize {0}".format(str(len(df))) print "Table {0} loaded to BI database with loadtime {1}".format(dest_table.name,loadtime) except: print "Table {0} could not be loaded".format(dest_table.name) rejected_list.append(dest_table.name) ,则导入成功。

这是我看到的那个人:

dst_schema

有人可以引导我找到可能的解决方案吗? 除了在将数据导入目标db sqlalchemy.exc.InternalError: (psycopg2.InternalError) cannot drop table A because other objects depend on it DETAIL: constraint fk_rails_111193 on table B depends on table A HINT: Use DROP ... CASCADE to drop the dependent objects too. [SQL: '\nDROP TABLE A'] 之前删除dst_schema之外,还有其他更好的选择吗?

(drop_dst_schema=true)

有没有人知道为什么def create_db(src,dst,src_schema,dst_schema,drop_dst_schema=True) 不会删除架构中的依赖项?我误解了这个对象吗?

1 个答案:

答案 0 :(得分:0)

您有几种选择:

每次都删除整个架构

如果您有一个复杂的架构,任何类型的闭环参考链,您最好的选择是始终放弃整个架构

您可以拥有一些自引用表(例如persons表,其自身关系类型为person parent-of person)。您还可以拥有一个模式,其中表A引用引用表A的表B.例如,您有一个表persons和一个companies,以及两个关系(可能与中间表一起):{{ 1}}和company employs persons

在这种情况下,这是切合实际的,无论你使用persons trade shares of companies做什么,这都行不通。

如果您实际上是从另一个数据库复制数据,并且能够负担得起时间,那么删除和重新创建整个模式是最容易实现的解决方案。您的代码将更加简单:需要考虑的案例更少。

DROP CASCADE

您也可以使用 sorted_tables 删除表格。如果一个表被另一个表引用,则会同时删除(或根据需要删除多个表)。您必须确保DROP CASCADEDROP的顺序为您提供预期的最终结果。我会非常仔细地检查这种情况是否适用于所有情况。

删除所有FK约束,然后在末尾重新创建它们

此外,还有最后一种可能性:在操作它们之前删除所有表的所有FK约束,并在最后重新创建它们。这样,您就可以随时删除任何表格。