简体   繁体   English

Python Pandas to_sql,如何创建带有主键的表?

[英]Python Pandas to_sql, how to create a table with a primary key?

I would like to create a MySQL table with Pandas' to_sql function which has a primary key (it is usually kind of good to have a primary key in a mysql table) as so:我想用 Pandas 的 to_sql 函数创建一个 MySQL 表,它有一个主键(在 mysql 表中有一个主键通常很好),如下所示:

group_export.to_sql(con = db, name = config.table_group_export, if_exists = 'replace', flavor = 'mysql', index = False)

but this creates a table without any primary key, (or even without any index).但这会创建一个没有任何主键(甚至没有任何索引)的表。

The documentation mentions the parameter 'index_label' which combined with the 'index' parameter could be used to create an index but doesn't mention any option for primary keys.该文档提到参数“index_label”与“index”参数结合可用于创建索引,但没有提及主键的任何选项。

Documentation 文档

Simply add the primary key after uploading the table with pandas.上传带有pandas的表后,只需添加主键即可。

group_export.to_sql(con=engine, name=example_table, if_exists='replace', 
                    flavor='mysql', index=False)

with engine.connect() as con:
    con.execute('ALTER TABLE `example_table` ADD PRIMARY KEY (`ID_column`);')

Disclaimer: this answer is more experimental then practical, but maybe worth mention.免责声明:这个答案更具实验性而不是实用,但也许值得一提。

I found that class pandas.io.sql.SQLTable has named argument key and if you assign it the name of the field then this field becomes the primary key:我发现类pandas.io.sql.SQLTable已命名参数key ,如果您为其分配字段名称,则该字段将成为主键:

Unfortunately you can't just transfer this argument from DataFrame.to_sql() function.不幸的是,您不能只从DataFrame.to_sql()函数传输这个参数。 To use it you should:要使用它,您应该:

  1. create pandas.io.SQLDatabase instance创建pandas.io.SQLDatabase实例

    engine = sa.create_engine('postgresql:///somedb') pandas_sql = pd.io.sql.pandasSQL_builder(engine, schema=None, flavor=None)
  2. define function analoguous to pandas.io.SQLDatabase.to_sql() but with additional *kwargs argument which is passed to pandas.io.SQLTable object created inside it (i've just copied original to_sql() method and added *kwargs ):定义pandas.io.SQLDatabase.to_sql()函数,但带有额外的*kwargs参数,该参数传递给在其中创建的pandas.io.SQLTable对象(我刚刚复制了原始的to_sql()方法并添加了*kwargs ):

     def to_sql_k(self, frame, name, if_exists='fail', index=True, index_label=None, schema=None, chunksize=None, dtype=None, **kwargs): if dtype is not None: from sqlalchemy.types import to_instance, TypeEngine for col, my_type in dtype.items(): if not isinstance(to_instance(my_type), TypeEngine): raise ValueError('The type of %s is not a SQLAlchemy ' 'type ' % col) table = pd.io.sql.SQLTable(name, self, frame=frame, index=index, if_exists=if_exists, index_label=index_label, schema=schema, dtype=dtype, **kwargs) table.create() table.insert(chunksize)
  3. call this function with your SQLDatabase instance and the dataframe you want to save使用您的SQLDatabase实例和要保存的数据SQLDatabase调用此函数

    to_sql_k(pandas_sql, df2save, 'tmp', index=True, index_label='id', keys='id', if_exists='replace')

And we get something like我们得到类似的东西

CREATE TABLE public.tmp
(
  id bigint NOT NULL DEFAULT nextval('tmp_id_seq'::regclass),
...
)

in the database.在数据库中。

PS You can of course monkey-patch DataFrame , io.SQLDatabase and io.to_sql() functions to use this workaround with convenience. PS 您当然可以使用猴子补丁DataFrameio.SQLDatabaseio.to_sql()函数来方便地使用此解决方法。

automap_base from sqlalchemy.ext.automap (tableNamesDict is a dict with only the Pandas tables): automap_basesqlalchemy.ext.automap (tableNamesDict仅与熊猫表的字典):

metadata = MetaData()
metadata.reflect(db.engine, only=tableNamesDict.values())
Base = automap_base(metadata=metadata)
Base.prepare()

Which would have worked perfectly, except for one problem, automap requires the tables to have a primary key .这本来可以完美运行,除了一个问题, automap 要求表具有主键 Ok, no problem, I'm sure Pandas to_sql has a way to indicate the primary key... nope.好的,没问题,我确定 Pandas to_sql有一种方法来指示主键......不。 This is where it gets a little hacky:这是它变得有点hacky的地方:

for df in dfs.keys():
    cols = dfs[df].columns
    cols = [str(col) for col in cols if 'id' in col.lower()]
    schema = pd.io.sql.get_schema(dfs[df],df, con=db.engine, keys=cols)
    db.engine.execute('DROP TABLE ' + df + ';')
    db.engine.execute(schema)
    dfs[df].to_sql(df,con=db.engine, index=False, if_exists='append')

I iterate thru the dict of DataFrames , get a list of the columns to use for the primary key (ie those containing id ), use get_schema to create the empty tables then append the DataFrame to the table.我遍历DataFramesdict ,获取用于主键的列列表(即那些包含id ),使用get_schema创建空表,然后将DataFrame附加到表中。

Now that you have the models, you can explicitly name and use them (ie User = Base.classes.user ) with session.query or create a dict of all the classes with something like this:现在你有了模型,你可以显式地命名和使用它们(即User = Base.classes.user )和session.query或者用这样的东西创建所有类的字典:

alchemyClassDict = {}
for t in Base.classes.keys():
    alchemyClassDict[t] = Base.classes[t]

And query with:并查询:

res = db.session.query(alchemyClassDict['user']).first()
with engine.connect() as con:
    con.execute('ALTER TABLE for_import_ml ADD PRIMARY KEY ("ID");')

for_import_ml is a table name in the database. for_import_ml是数据库中的表名。

Adding a slight variation to tomp's answer (I would comment but don't have enough reputation points).为 tomp 的答案添加一些细微的变化(我会发表评论,但没有足够的声望点)。

I am using PGAdmin with Postgres (on Heroku) to check and it works.我正在使用带有 Postgres(在 Heroku 上)的 PGAdmin 来检查它是否有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM