DataFrameをpostgresテーブルに書き込む方法は?


103

DataFrame.to_sqlメソッドがありますが、これはmysql、sqlite、およびoracleデータベースでのみ機能します。このメソッドにpostgres接続またはsqlalchemyエンジンを渡すことができません。

回答:


125

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)

バージョン0.13.1までのパンダではpostgresqlはサポートされていなかったのはあなたです。古いバージョンのパンダを使用する必要がある場合は、次のパッチを適用したバージョンがあり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')

1
これで0.14になりましたか?
クワント

はい、また0.15はすでにリリースされています(リリース候補)。質問をありがとう、答えを更新します。
joris 2014年

1
この投稿は、私のために問題を解決:stackoverflow.com/questions/24189150/...
srodriguex

注:to_sqlはpostgresの配列型をエクスポートしません。
Saurabh Saha

1
新しいを作成する代わりにSqlalchemy engine、を使用してPostgres作成された既存の接続を使用できpsycopg2.connect()ますか?
ジャービス

83

より高速なオプション:

次のコードは、Pandas DFをdf.to_sqlメソッドよりもはるかに高速にpostgres DBにコピーし、dfを格納するための中間csvファイルを必要としません。

DB仕様に基づいてエンジンを作成します。

データフレーム(df)と同じ数の列を持つpostgres DBにテーブルを作成します。

DFのデータがpostgresテーブルに挿入されます。

from sqlalchemy import create_engine
import psycopg2 
import io

テーブルを置き換える場合は、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()

変数contentsは何をしますか?これで書かれたものである必要がありcopy_from()ますか?
n1000

@ n1000 contents変数を無視するだけで、他のすべては問題なく機能するはずです
Bobby

2
なぜあなたはしoutput.seek(0)ますか?
moshevi 2018

7
これは非常に速いのでおもしろい:D
shadi

1
一部のフィールドに改行文字が含まれているため、テーブルの読み込みが失敗します。これをどのように処理しますか?df.to_csv(output、sep = '\ t'、header = False、index = False、encoding = 'utf-8')cur.copy_from(output、 'messages'、null = "")#null値は ''
conetfun

22

Pandas 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)

3
ほとんどのmethod='multi'場合、追加オプションは十分高速です。しかし、はい、このCOPY方法が現在最速の方法です。
ソード

これはcsv専用ですか?.xlsxでも使用できますか?これの各部分が何をしているのかについてのいくつかのメモは役に立ちます。後の最初の部分withは、メモリ内バッファへの書き込みです。の最後の部分でwithは、SQLステートメントを使用し、copy_expertの速度を利用してデータをバルクロードします。始めることから始まる中間部分は何columns =ですか?
DudeWah

これは私にとって非常にうまくいきました。そして、あなたkeyspsql_insert_copy関数の引数を説明できますか?どのようにしてキーを取得し、キーは列名だけですか?
Bowen Liu

このメソッドを使用しようとしましたが、エラーがスローされますTable 'XYZ' already exists。私が理解している限り、テーブルを作成するべきではありませんか?
E. Epstein

@ E.Epstein-最後の行を次のように変更できますdf.to_sql('table_name', engine, if_exists='replace', method=psql_insert_copy)-これにより、データベースにテーブルが作成されます。
mgoldwasser

21

これは私がやった方法です。

次を使用しているため、より高速になる可能性があります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()

1
私はAttributeErrorを受け取ります:モジュール 'psycopg2'には属性 'extras'がありません。ああ、これは明示的にインポートする必要があります。psycopg2.extrasのインポート
GeorgeLPerkins

この関数はsqlalchemyソリューションよりもはるかに高速です
Saurabh Saha

0

Python 2.7およびPandas 0.24.2で、Psycopg2を使用する場合

Psycopg2接続モジュール

def dbConnect (db_parm, username_parm, host_parm, pw_parm):
    # Parse in connection information
    credentials = {'host': host_parm, 'database': db_parm, 'user': username_parm, 'password': pw_parm}
    conn = psycopg2.connect(**credentials)
    conn.autocommit = True  # auto-commit each entry to the database
    conn.cursor_factory = RealDictCursor
    cur = conn.cursor()
    print ("Connected Successfully to DB: " + str(db_parm) + "@" + str(host_parm))
    return conn, cur

データベースに接続する

conn, cur = dbConnect(databaseName, dbUser, dbHost, dbPwd)

データフレームがすでにdfとして存在すると仮定

output = io.BytesIO() # For Python3 use StringIO
df.to_csv(output, sep='\t', header=True, index=False)
output.seek(0) # Required for rewinding the String object
copy_query = "COPY mem_info FROM STDOUT csv DELIMITER '\t' NULL ''  ESCAPE '\\' HEADER "  # Replace your table name in place of mem_info
cur.copy_expert(copy_query, output)
conn.commit()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.