次のように、主キーを持つ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」が記載されていますが、主キーのオプションは記載されていません。
免責事項:この答えは実用的というより実験的ですが、言及する価値があるかもしれません。
クラスpandas.io.sql.SQLTable
には名前付き引数key
があり、フィールドの名前を割り当てると、このフィールドが主キーになることがわかりました。
残念ながら、この引数をDataFrame.to_sql()
関数から転送することはできません。それを使用するには、次のことを行う必要があります。
pandas.io.SQLDatabase
インスタンスを作成します
engine = sa.create_engine('postgresql:///somedb')
pandas_sql = pd.io.sql.pandasSQL_builder(engine, schema=None, flavor=None)
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)
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もちろん、モンキーパッチDataFrame
、io.SQLDatabase
、およびio.to_sql()
関数を使用して、この回避策を便利に使用できます。
パンダでテーブルをアップロードした後、主キーを追加するだけです。
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`);')
automap_base
from sqlalchemy.ext.automap
(tableNamesDictは、Pandasテーブル)のみを持つ辞書です。
metadata = MetaData()
metadata.reflect(db.engine, only=tableNamesDict.values())
Base = automap_base(metadata=metadata)
Base.prepare()
これは完全に機能しますが、1つの問題を除いて、自動マップにはテーブルに主キーが必要です。 OK、問題ない、きっとPandas to_sql
には主キーを示す方法があります...これは少しハックがかかるところです:
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')
dict
のDataFrames
を反復処理し、主キー(つまり、id
を含む列)に使用する列のリストを取得し、get_schema
を使用して空のテーブルを作成し、DataFrame
をテーブルに追加します。
モデルができたので、明示的に名前を付けて使用できます(つまり、User = Base.classes.user
)session.query
または、次のようなすべてのクラスの辞書を作成します。
alchemyClassDict = {}
for t in Base.classes.keys():
alchemyClassDict[t] = Base.classes[t]
そしてクエリ:
res = db.session.query(alchemyClassDict['user']).first()