Як записати DataFrame в таблицю postgres?


103

Існує метод DataFrame.to_sql , але він працює лише для баз даних mysql, sqlite та oracle. Я не можу перейти до цього методу підключення postgres або движка sqlalchemy.

Відповіді:


125

Починаючи з pandas 0.14 (випущено в кінці травня 2014 року), postgresql підтримується. sqlМодуль тепер використовується sqlalchemyдля підтримки різних смаків бази даних. Ви можете передати механізм sqlalchemy для бази даних postgresql (див. Документи ). Наприклад:

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 .
Я писав це давно, тому не можу повністю гарантувати, що це завжди працює, але основа там повинна бути). Якщо ви помістите цей файл у свій робочий каталог та імпортуєте його, тоді ви зможете зробити (де conз'єднання postgresql):

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

1
Це повідомлення вирішити цю проблему для мене: stackoverflow.com/questions/24189150 / ...
srodriguex

Примітка: to_sql не експортує типи масивів у postgres.
Saurabh Saha

1
Замість створення нового Sqlalchemy engine, чи можу я використати існуюче Postgresз'єднання, створене за допомогою psycopg2.connect()?
Джарвіс,

84

Швидший варіант:

Наступний код скопіює ваш Pandas DF у БД postgres набагато швидше, ніж метод df.to_sql, і вам не знадобиться проміжний файл csv для зберігання df.

Створіть двигун на основі специфікацій БД.

Створіть таблицю у вашій БД postgres, яка має однакову кількість стовпців як Dataframe (df).

Дані в DF будуть вставлятися у вашу таблицю postgres.

from sqlalchemy import create_engine
import psycopg2 
import io

якщо ви хочете замінити таблицю, ми можемо замінити її звичайним методом to_sql, використовуючи заголовки нашого df, а потім завантажити весь великий трудомісткий df в БД.

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змінну, все інше має працювати нормально
Боббі

2
чому ти робиш output.seek(0)?
мошеві

7
Це настільки швидко, що це смішно: D
shadi

1
Завантажити таблицю мені не вдається через нові рядкові символи в деяких полях. Як я з цим справляюся? df.to_csv (output, sep = '\ t', header = False, index = False, encoding = 'utf-8') cur.copy_from (output, 'messages', null = "") # нульові значення стають ''
conetfun

23

Розчин 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метод зараз є найшвидшим способом.
ssword

Це лише для csv? Чи можна його використовувати також із .xlsx? Деякі примітки щодо того, що робить кожна частина цього, були б корисними. Перша частина після - withце запис у буфер пам'яті. Остання частина with- використання оператора SQL та використання швидкості copy_expert для масового завантаження даних. Що таке середня частина, яка починається з columns =виконання?
DudeWah

Це дуже добре спрацювало для мене. І чи можете ви пояснити keysаргументи у psql_insert_copyфункції, будь ласка? Як він отримує будь-які ключі, і чи є ключі лише назвами стовпців?
Боуен Лю

Я спробував з допомогою цього методу, однак він видає мені помилку: Table 'XYZ' already exists. Наскільки я розумію, це не повинно створювати таблицю, чи не так?
Е. Епштейн,

@ 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'. Ах, це потрібно явно імпортувати. import psycopg2.extras
GeorgeLPerkins

ця функція набагато швидша, ніж рішення sqlalchemy
Saurabh Saha

-1

Для 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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.