Respostas:
A partir do pandas 0.14 (lançado no final de maio de 2014), o postgresql é compatível. O sql
módulo agora usa sqlalchemy
para suportar diferentes tipos de banco de dados. Você pode passar um mecanismo sqlalchemy para um banco de dados postgresql (consulte os documentos ). Por exemplo:
from sqlalchemy import create_engine
engine = create_engine('postgresql://scott:tiger@localhost:5432/mydatabase')
df.to_sql('table_name', engine)
Você está correto que nos pandas até a versão 0.13.1 postgresql não era suportado. Se você precisar usar uma versão mais antiga do pandas, aqui está uma versão corrigida de pandas.io.sql
: https://gist.github.com/jorisvandenbossche/10841234 .
Eu escrevi isso há um tempo atrás, então não posso garantir totalmente que sempre funcione, mas a base deve estar lá). Se você colocar esse arquivo em seu diretório de trabalho e importá-lo, deverá ser capaz de fazer (onde con
está uma conexão postgresql):
import sql # the patched version (file is named sql.py)
sql.write_frame(df, 'table_name', con, flavor='postgresql')
Sqlalchemy engine
, posso usar uma Postgres
conexão existente criada usando psycopg2.connect()
?
Opção mais rápida:
O código a seguir copiará seu Pandas DF para o banco de dados postgres muito mais rápido do que o método df.to_sql e você não precisará de nenhum arquivo csv intermediário para armazenar o df.
Crie um motor com base nas especificações do seu banco de dados.
Crie uma tabela em seu banco de dados postgres que tenha o mesmo número de colunas do Dataframe (df).
Os dados no DF serão inseridos em sua tabela postgres.
from sqlalchemy import create_engine
import psycopg2
import io
se você quiser substituir a tabela, podemos substituí-la pelo método to_sql normal usando cabeçalhos de nosso df e, em seguida, carregar todo o df que consome muito tempo no banco de dados.
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
faz? Deve ser este o que está escrito copy_from()
?
contents
variável, todo o resto deve funcionar bem
output.seek(0)
?
Solução Pandas 0.24.0+
No Pandas 0.24.0 foi introduzido um novo recurso projetado especificamente para gravações rápidas no Postgres. Você pode saber mais sobre isso aqui: 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)
method='multi'
opção é rápido o suficiente. Mas sim, este COPY
método é o caminho mais rápido agora.
with
está escrevendo em um buffer de memória. A última parte do with
é usar uma instrução SQL e aproveitar a velocidade de copy_expert para carregar os dados em massa. Qual é a parte do meio que começa columns =
fazendo?
keys
argumentos da psql_insert_copy
função, por favor? Como ele obtém quaisquer chaves e as chaves são apenas os nomes das colunas?
Table 'XYZ' already exists
. Pelo que entendi, não deveria criar uma mesa, deveria?
df.to_sql('table_name', engine, if_exists='replace', method=psql_insert_copy)
- isso cria uma tabela em seu banco de dados.
É assim que eu fiz.
Pode ser mais rápido porque está usando 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()
Para Python 2.7 e Pandas 0.24.2 e usando Psycopg2
Módulo de conexão 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
Conecte-se ao banco de dados
conn, cur = dbConnect(databaseName, dbUser, dbHost, dbPwd)
Supondo que o dataframe já esteja presente como 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()