45

我想用 Pandas 的 to_sql 函数创建一个 MySQL 表,它有一个主键(在 mysql 表中有一个主键通常很好),如下所示:

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

但这会创建一个没有任何主键(甚至没有任何索引)的表。

该文档提到了与“index”参数结合使用的参数“index_label”可用于创建索引,但没有提及主键的任何选项。

文档

4

5 回答 5

63

只需在使用 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`);')
于 2016-11-23T17:30:58.450 回答
26

免责声明:这个答案比实际更实验性,但也许值得一提。

我发现该类pandas.io.sql.SQLTable具有命名参数key,如果您为其分配字段的名称,则该字段将成为主键:

不幸的是,你不能只从DataFrame.to_sql()函数中转移这个参数。要使用它,您应该:

  1. 创建pandas.io.SQLDatabase实例

    engine = sa.create_engine('postgresql:///somedb')
    pandas_sql = pd.io.sql.pandasSQL_builder(engine, schema=None, flavor=None)
    
  2. 定义类似于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. SQLDatabase使用您的实例和要保存的数据框调用此函数

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

我们得到类似的东西

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

在数据库中。

PS您当然可以使用 Monkey-patchDataFrame和函数来方便io.SQLDatabaseio.to_sql()使用此解决方法。

于 2015-06-25T08:29:44.357 回答
5

从 pandas 0.15 开始,至少对于某些风格,您可以使用参数dtype来定义主键列。您甚至可以通过AUTOINCREMENT这种方式激活。对于 sqlite3,这看起来像这样:

import sqlite3
import pandas as pd

df = pd.DataFrame({'MyID': [1, 2, 3], 'Data': [3, 2, 6]})
with sqlite3.connect('foo.db') as con:
    df.to_sql('df', con=con, dtype={'MyID': 'INTEGER PRIMARY KEY AUTOINCREMENT'})
于 2021-09-27T17:19:48.970 回答
0

automap_base来自sqlalchemy.ext.automap(tableNamesDict 是一个只有 Pandas 表的字典):

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

这本来可以完美运行,除了一个问题,automap 要求表有一个 primary key。好的,没问题,我确信 Pandasto_sql有办法指示主键......不。这是它变得有点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')

我遍历dictof DataFrames,获取用于主键的列列表(即包含 的列id),用于get_schema创建空表,然后将 附加DataFrame到表中。

现在您有了模型,您可以显式地命名和使用它们(即User = Base.classes.usersession.query或创建所有类的字典,如下所示:

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

并查询:

res = db.session.query(alchemyClassDict['user']).first()
于 2016-02-14T21:04:08.127 回答
0
with engine.connect() as con:
    con.execute('ALTER TABLE for_import_ml ADD PRIMARY KEY ("ID");')

for_import_ml是数据库中的表名。

为 tomp 的答案添加一些细微的变化(我会发表评论,但没有足够的声誉点)。

我正在使用 PGAdmin 和 Postgres(在 Heroku 上)进行检查,它可以工作。

于 2021-02-14T17:07:00.930 回答