如何将DataFrame写入postgres表?

m9_*_*psy 74 python postgresql sqlalchemy pandas

DataFrame.to_sql方法,但它只适用于mysql,sqlite和oracle数据库.我不能传递给这种方法postgres连接或sqlalchemy引擎.

jor*_*ris 95

从pandas 0.14(2014年5月底发布)开始,支持postgresql.该sql模块现在用于sqlalchemy支持不同的数据库风格.您可以为postgresql数据库传递sqlalchemy引擎(请参阅docs).例如:

from sqlalchemy import create_engine
engine = create_engine('postgresql://scott:tiger@localhost:5432/mydatabase')
df.to_sql('table_name', engine)
Run Code Online (Sandbox Code Playgroud)

你是正确的,在pandas到0.13.1版本的postgresql不支持.如果您需要使用旧版本的pandas,请参阅以下版本pandas.io.sql:https://gist.github.com/jorisvandenbossche/10841234.
我前一段时间写过这篇文章,所以不能完全保证它始终有效,但基础应该在那里).如果您将该文件放在工作目录中并导入它,那么您应该能够做到(conpostgresql连接在哪里):

import sql  # the patched version (file is named sql.py)
sql.write_frame(df, 'table_name', con, flavor='postgresql')
Run Code Online (Sandbox Code Playgroud)

  • 我可以使用使用“psycopg2.connect()”创建的现有“Postgres”连接,而不是创建新的“Sqlalchemy 引擎”吗? (7认同)
  • 注意:to_sql 不导出 postgres 中的数组类型。 (2认同)
  • 对于写表来说,这是不可能的。它需要是 sqlalchemy 引擎或连接。 (2认同)

Ase*_*eem 63

更快的选择:

以下代码将比df.to_sql方法更快地将您的Pandas DF复制到postgres DB,并且您不需要任何中间csv文件来存储df.

根据您的数据库规范创建引擎.

在postgres DB中创建一个与Dataframe(df)列数相同的表.

DF中的数据将插入到postgres表中.

from sqlalchemy import create_engine
import psycopg2 
import io
Run Code Online (Sandbox Code Playgroud)

如果你想替换表,我们可以使用来自df的头文件用普通的to_sql方法替换它,然后将整个耗费大量时间的df加载到DB中.

engine = create_engine('postgresql+psycopg2://username:password@host:port/database')

df.head(0).to_sql('table_name', engine, if_exists='replace',index=False) #truncates the table

conn = engine.raw_connection()
cur = conn.cursor()
output = io.StringIO()
df.to_csv(output, sep='\t', header=False, index=False)
output.seek(0)
contents = output.getvalue()
cur.copy_from(output, 'table_name', null="") # null values become ''
conn.commit()
Run Code Online (Sandbox Code Playgroud)

  • 三年后,我再次降落在这里...... ́\\_(ツ)_/̊ (9认同)
  • 你为什么要做`output.seek(0)`? (5认同)
  • 变量“contents”有什么作用?这应该是`copy_from()`中写的吗? (3认同)
  • 这是如此之快以至于很有趣:D (3认同)
  • 为了将数据写入特定模式,从 `psycopg` 2.9 版本开始,您不能再使用 `cur.copy_from` 方法: 2.9 版本中的更改:表和字段名称现在被引用。如果您需要指定模式限定表,请使用“copy_expert()”。这是 copy_expert 的样子: `cur.copy_expert('COPY schema_name.table_name FROM STDIN', output)` (3认同)
  • 测试结果:`.to_sql` 27秒(与通过DataGrip导入csv相同),此方法8秒。形状 = (1,000,000, 3) (3认同)
  • 如果要使用 schema,可以在代码的 `to_sql` 部分添加 `schema=your_schema` 参数。 (2认同)

Beh*_*ani 14

我就是这样做的,因为它使用的是execute_batch,所以我可能会更快:

# df is the dataframe
if len(df) > 0:
    df_columns = list(df)
    # create (col1,col2,...)
    columns = ",".join(df_columns)

    # create VALUES('%s', '%s",...) one '%s' per column
    values = "VALUES({})".format(",".join(["%s" for _ in df_columns])) 

    #create INSERT INTO table (columns) VALUES('%s',...)
    insert_stmt = "INSERT INTO {} ({}) {}".format(table,columns,values)

    cur = conn.cursor()
    psycopg2.extras.execute_batch(cur, insert_stmt, df.values)
    conn.commit()
    cur.close()
Run Code Online (Sandbox Code Playgroud)

  • 我得到 AttributeError: module 'psycopg2' has no attribute 'extras'。啊,这需要显式导入。导入 psycopg2.extras (2认同)

mgo*_*ser 12

熊猫0.24.0+解决方案

在Pandas 0.24.0中引入了一个新功能,该功能是专为快速写入Postgres设计的。您可以在此处了解更多信息:https : //pandas.pydata.org/pandas-docs/stable/user_guide/io.html#io-sql-method

import csv
from io import StringIO

from sqlalchemy import create_engine

def psql_insert_copy(table, conn, keys, data_iter):
    # gets a DBAPI connection that can provide a cursor
    dbapi_conn = conn.connection
    with dbapi_conn.cursor() as cur:
        s_buf = StringIO()
        writer = csv.writer(s_buf)
        writer.writerows(data_iter)
        s_buf.seek(0)

        columns = ', '.join('"{}"'.format(k) for k in keys)
        if table.schema:
            table_name = '{}.{}'.format(table.schema, table.name)
        else:
            table_name = table.name

        sql = 'COPY {} ({}) FROM STDIN WITH CSV'.format(
            table_name, columns)
        cur.copy_expert(sql=sql, file=s_buf)

engine = create_engine('postgresql://myusername:mypassword@myhost:5432/mydatabase')
df.to_sql('table_name', engine, method=psql_insert_copy)
Run Code Online (Sandbox Code Playgroud)

  • 大多数情况下,添加`method='multi'` 选项就足够快了。但是是的,这种`COPY` 方法是目前最快的方法。 (4认同)