Làm thế nào để ghi DataFrame vào bảng postgres?


103

Có phương thức DataFrame.to_sql , nhưng nó chỉ hoạt động cho cơ sở dữ liệu mysql, sqlite và oracle. Tôi không thể chuyển đến phương pháp này kết nối postgres hoặc công cụ sqlalchemy.

Câu trả lời:


125

Bắt đầu từ pandas 0.14 (phát hành cuối tháng 5 năm 2014), postgresql được hỗ trợ. Các sqlmô-đun bây giờ sử dụng sqlalchemyđể hỗ trợ cơ sở dữ liệu hương vị khác nhau. Bạn có thể chuyển một công cụ sqlalchemy cho cơ sở dữ liệu postgresql (xem tài liệu ). Ví dụ:

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

Bạn đúng rằng ở gấu trúc lên đến phiên bản 0.13.1 postgresql không được hỗ trợ. Nếu bạn cần sử dụng phiên bản gấu trúc cũ hơn, đây là phiên bản vá của pandas.io.sql: https://gist.github.com/jorisvandenbossche/10841234 .
Tôi đã viết điều này một thời gian trước, vì vậy không thể đảm bảo hoàn toàn rằng nó luôn hoạt động, nhưng cơ sở nên có). Nếu bạn đặt tệp đó vào thư mục làm việc của mình và nhập nó, thì bạn sẽ có thể làm được ( conkết nối postgresql ở đâu):

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

1
Điều này có làm cho nó đến 0,14?
Quant

Có, và 0,15 cũng đã được phát hành (ứng cử viên phát hành). Tôi sẽ cập nhật câu trả lời, cảm ơn vì đã hỏi.
joris

1
Bài viết này đã giải quyết được vấn đề đối với tôi: stackoverflow.com/questions/24189150/...
srodriguex

Lưu ý: to_sql không xuất các kiểu mảng trong postgres.
Saurabh Saha

1
Thay vì tạo mới Sqlalchemy engine, tôi có thể sử dụng Postgreskết nối hiện có được tạo bằng cách sử dụng psycopg2.connect()không?
Jarvis

84

Tùy chọn nhanh hơn:

Đoạn mã sau sẽ sao chép Pandas DF của bạn vào DB postgres nhanh hơn nhiều so với phương thức df.to_sql và bạn sẽ không cần bất kỳ tệp csv trung gian nào để lưu trữ df.

Tạo một công cụ dựa trên thông số kỹ thuật DB của bạn.

Tạo một bảng trong DB postgres của bạn có số cột bằng Dataframe (df).

Dữ liệu trong DF sẽ được chèn vào bảng postgres của bạn.

from sqlalchemy import create_engine
import psycopg2 
import io

nếu bạn muốn thay thế bảng, chúng ta có thể thay thế nó bằng phương thức to_sql bình thường bằng cách sử dụng các tiêu đề từ df của chúng ta và sau đó tải toàn bộ df tốn nhiều thời gian vào 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()

Biến contentslàm gì? Đây có nên là một trong những được viết trong copy_from()?
n1000

@ n1000 Vâng chỉ cần bỏ qua contentsbiến, mọi thứ khác sẽ hoạt động tốt
Bobby

2
tại sao bạn làm output.seek(0)?
moshevi 20/09/18

7
Nhanh quá nên buồn cười: D
shadi 21/09/18

1
Bảng tải là không thành công đối với tôi do các ký tự dòng mới trong một số trường. Làm thế nào để tôi xử lý điều này? df.to_csv (output, sep = '\ t', header = False, index = False, encoding = 'utf-8') cur.copy_from (output, 'messages', null = "") # giá trị null trở thành ''
conetfun

23

Giải pháp gấu trúc 0.24.0+

Trong Pandas 0.24.0, một tính năng mới đã được giới thiệu được thiết kế đặc biệt để ghi nhanh vào Postgres. Bạn có thể tìm hiểu thêm về nó tại đây: 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
Trong hầu hết thời gian, method='multi'tùy chọn thêm là đủ nhanh. Nhưng có, COPYphương pháp này là cách nhanh nhất hiện nay.
ssword

Đây có phải là chỉ dành cho csv không? Nó có thể được sử dụng với .xlsx không? Một số ghi chú về những gì mỗi phần của điều này đang làm sẽ hữu ích. Phần đầu tiên sau khi withđược ghi vào một bộ đệm trong bộ nhớ. Phần cuối cùng withlà sử dụng câu lệnh SQL và tận dụng tốc độ của copy_expert để tải dữ liệu hàng loạt. Phần giữa bắt đầu với columns =việc làm gì?
DudeWah 31-07-19

Điều này làm việc rất tốt cho tôi. Và bạn có thể giải thích các keysđối số trong psql_insert_copyhàm được không? Làm thế nào nó nhận được bất kỳ khóa nào và các khóa chỉ là tên cột?
Bowen Liu

Tôi đã cố gắng sử dụng phương pháp này, tuy nhiên nó ném cho tôi một lỗi: Table 'XYZ' already exists. Theo như tôi hiểu, nó không nên tạo một bảng, phải không?
E. Epstein

@ E.Epstein - bạn có thể sửa đổi dòng cuối cùng thành df.to_sql('table_name', engine, if_exists='replace', method=psql_insert_copy)- điều này sẽ tạo một bảng trong cơ sở dữ liệu của bạn.
mgoldwasser

21

Đây là cách tôi đã làm điều đó.

Nó có thể nhanh hơn vì nó đang sử dụng 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
Tôi nhận được AttributeError: mô-đun 'psycopg2' không có thuộc tính 'bổ sung'. Ah, điều này cần được nhập rõ ràng. nhập psycopg2.extras
GeorgeLPerkins

chức năng này là nhanh hơn nhiều so với các giải pháp SQLAlchemy
Saurabh Saha

-1

Đối với Python 2.7 và Pandas 0.24.2 và sử dụng Psycopg2

Mô-đun kết nối 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

Kết nối với cơ sở dữ liệu

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

Giả sử dataframe đã có sẵn dưới dạng 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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.