DataFrame'i postgres tablosuna nasıl yazabilirim?


109

DataFrame.to_sql metodu var ama sadece mysql, sqlite ve oracle veritabanları için çalışıyor. Bu yönteme postgres bağlantı veya sqlalchemy motoruna geçemiyorum.

Yanıtlar:


132

Pandalar 0.14'ten başlayarak (Mayıs 2014 sonunda piyasaya sürüldü) postgresql desteklenmektedir. sqlModül şimdi kullandığı sqlalchemyfarklı veritabanı tatlar destekleyecek. Postgresql veritabanı için bir sqlalchemy motorunu geçebilirsiniz ( belgelere bakın ). Örneğin:

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

0.13.1 postgresql sürümüne kadar olan pandalarda desteklenmediğini doğru söylüyorsunuz. Pandaların daha eski bir sürümünü kullanmanız gerekiyorsa, şuranın yamalı sürümünü burada bulabilirsiniz pandas.io.sql: https://gist.github.com/jorisvandenbossche/10841234 .
Bunu bir süre önce yazdım, bu yüzden her zaman işe yarayacağını tam olarak garanti edemem, ama temel orada olmalı). Bu dosyayı çalışma dizininize koyup içe aktarırsanız, şunları yapabilmeniz gerekir ( conpostgresql bağlantısı nerede ):

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

1
Bu 0.14'e ulaştı mı?
Quant

Evet, ayrıca 0.15 zaten yayınlandı (sürüm adayı). Cevabı güncelleyeceğim, sorduğun için teşekkürler.
joris

1
Bu gönderi benim için sorunu çözdü: stackoverflow.com/questions/24189150/…
srodriguex

Not: to_sql, postgres'te dizi türlerini dışa aktarmaz.
Saurabh Saha

1
Yeni Sqlalchemy enginebir Postgresbağlantı oluşturmak yerine, kullanılarak oluşturulmuş mevcut bir bağlantıyı kullanabilir miyim psycopg2.connect()?
Underoos

93

Daha hızlı seçenek:

Aşağıdaki kod, Pandas DF'nizi postgres DB'ye df.to_sql yönteminden çok daha hızlı kopyalayacaktır ve df'yi depolamak için herhangi bir ara csv dosyasına ihtiyacınız olmayacaktır.

DB spesifikasyonlarınıza göre bir motor oluşturun.

Postgres DB'nizde Dataframe (df) ile eşit sayıda sütuna sahip bir tablo oluşturun.

DF'deki veriler postgres tablonuza eklenecektir .

from sqlalchemy import create_engine
import psycopg2 
import io

tabloyu değiştirmek isterseniz, onu normal to_sql metodu ile değiştirebiliriz ve df'deki başlıkları kullanarak büyük zaman alan df'yi DB'ye yükleyebiliriz.

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

Değişken ne yapar contents? Yazılan bu olmalı mı copy_from()?
n1000

3
neden yaparsınız output.seek(0)?
moshevi

10
Bu o kadar hızlı ki komik: D
shadi

1
Bazı alanlardaki yeni satır karakterleri nedeniyle yük tablası benim için başarısız oluyor. Bunu nasıl hallederim? df.to_csv (output, sep = '\ t', header = False, index = False, encoding = 'utf-8') cur.copy_from (output, 'messages', null = "") # boş değerler ''
conetfun

1
@moshevi - arama yöntemi Dosyanın mevcut konumunu belirler, bu nedenle burada konumu açıkça dosyanın başlangıcına geri taşır
foakesm

27

Pandas 0.24.0+ çözümü

Pandas 0.24.0'da, Postgres'e hızlı yazma için özel olarak tasarlanmış yeni bir özellik sunuldu. Buradan daha fazla bilgi edinebilirsiniz: 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
Çoğu zaman, ekleme method='multi'seçeneği yeterince hızlıdır. Ama evet, bu COPYyöntem şu anda en hızlı yoldur.
ssword

Bu sadece csv'ler için mi? .Xlsx ile de kullanılabilir mi? Bunun her bir parçasının ne yaptığına dair bazı notlar yardımcı olacaktır. Bundan sonraki ilk bölüm withbir ara belleğe yazmaktır. Son kısmı, withbir SQL ifadesi kullanmak ve verileri toplu olarak yüklemek için copy_expert'in hızından yararlanmaktır. Yapmakla başlayan orta kısım nedir columns =?
DudeWah

Bu benim için çok iyi çalıştı. Ve fonksiyondaki keysargümanları açıklar psql_insert_copymısınız lütfen? Anahtarları nasıl alıyor ve anahtarlar sadece sütun adları mı?
Bowen Liu,

Ben ancak bana bir hata atar, bu yöntem kullanılarak denedim: Table 'XYZ' already exists. Anladığım kadarıyla bir tablo oluşturmamalı, değil mi?
E. Epstein

@ E.Epstein - son satırı şu şekilde değiştirebilirsiniz df.to_sql('table_name', engine, if_exists='replace', method=psql_insert_copy)- bu, veritabanınızda bir tablo oluşturur.
mgoldwasser

24

Ben böyle yaptım.

Daha hızlı olabilir çünkü şunları kullanıyor 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 alıyorum: "psycopg2" modülünün "ekstralar" özelliği yok. Ah, bunun açıkça içe aktarılması gerekiyor. import psycopg2.extras
GeorgeLPerkins

bu işlev sqlalchemy çözümünden çok daha hızlı
Saurabh Saha

-1

Python 2.7 ve Pandas 0.24.2 için ve Psycopg2 kullanımı

Psycopg2 Bağlantı Modülü

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

Veritabanına bağlanın

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

Veri çerçevesinin zaten df olarak mevcut olduğunu varsayarsak

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()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.