使用Pandas在MySQL中创建临时表

ltskdhd1  于 2022-10-31  发布在  Mysql
关注(0)|答案(3)|浏览(394)

Pandas有一个很棒的特性,你可以在SQL中将 Dataframe 写入一个表。
df.to_sql(con=cnx, name='some_table_name', if_exists='replace', flavor='mysql', index=False)
有没有办法这样做一个临时表?
据我所知,文档中没有任何内容。

bprjcwpo

bprjcwpo1#

DataFrame.to_sql()使用内置的panda pandas.io.sql包,它本身依赖于SQLAlchemy作为数据库抽象层。为了在SQLAlchemy ORM中创建一个“临时”表,you need to supply a prefix

t = Table(
    't', metadata,
    Column('id', Integer, primary_key=True),
    # ...
    prefixes=['TEMPORARY'],
)

据我所知,pandas.io.sql不允许指定prefixes,也不允许轻松地更改表的创建方式。
解决此问题的一种方法是 * 预先创建临时表 *,并将to_sql()if_exists="append"一起使用(所有这些都使用同一个数据库连接)。
下面也是我尝试做的事情:重写pandas.io.sql.SQLTable_create_table_setup()方法,并将prefixes传递给Table构造函数。由于某些原因,该表仍然是非临时创建的。不确定是否有帮助,但以下是我使用的代码:gist。这是一种很老套的方法,但我希望它至少可以作为一个示例代码,让您开始使用这种方法。

jutyujz0

jutyujz02#

简单的解决方案,无需花哨的魔法

对我来说,这是一个快速而简单的变通办法。
只需将RegEx应用于生成的SQL,即可添加所需的任何语句。

import io
import pandas as pd

# Get the SQL that would be generated by the create table statement

create_table_sql = pd.io.sql.get_schema(df, tmp_table_name)

# Replace the `CREATE TABLE` part of the generated statement with

# whatever you need.

create_tmp_table_sql = re.sub(
    "^(CREATE TABLE)?",
    "CREATE TEMP TABLE",
    create_table_sql
)

然后,您可以像这样使用它:


# Write to the database in a transaction (psycopg2)

with conn.cursor() as cur:
    cur.execute(create_tmp_table_sql)
    output = io.StringIO()
    df.to_csv(output, sep="\t", header=False, index=False, na_rep="NULL")
    output.seek(0)
    cur.copy_from(output, tmp_table_name, null="NULL")

归功于Aseem,它提供了一种快速写入Postgres的方法。

vu8f3i0k

vu8f3i0k3#

这可能有点笨拙,而且从技术上讲,它并没有创建临时表,它只是像一个临时表一样工作,但是你可以使用contextlib中的@contextmanager装饰器在打开上下文时创建表,并在关闭上下文时删除它。

from contextlib import contextmanager

import numpy as np
import sqlalchemy as sqla
import pandas as pd

@contextmanager
def temp_table(frame, tbl, eng, *args,**kwargs):
    frame.to_sql(tbl, eng, *args,**kwargs)
    yield
    eng.execute('DROP TABLE {}'.format(tbl))

df = pd.DataFrame(np.random.randint(21, size=(10, 10)))
cnx = sqla.create_engine(conn_string)

with temp_table(df, 'some_table_name', cnx, if_exists='replace', flavor='mysql', index=False):
    # do stuff with "some_table_name"

我用Teradata测试了它,它运行得很好。我没有MySQL可以测试它,但是只要DROP语句在MySQL中工作,它就应该能按预期工作。

相关问题