SQLAlchemy,Psycopg2和Postgresql COPY

Eog*_*anM 19 postgresql sqlalchemy psycopg2

看起来Psycopg有一个用于执行COPY的自定义命令:

psycopg2 COPY使用cursor.copy_from()冻结大输入

有没有办法从SQLAlchemy访问此功能?

dnf*_*ren 34

接受的答案是正确的,但如果你想要的不只是EoghanM的评论继续下面的工作,请将表格复制到CSV ...

from sqlalchemy import sessionmaker, create_engine

eng = create_engine("postgresql://user:pwd@host:5432/db")
ses = sessionmaker(bind=engine)

dbcopy_f = open('/tmp/some_table_copy.csv','wb')

copy_sql = 'COPY some_table TO STDOUT WITH CSV HEADER'

fake_conn = eng.raw_connection()
fake_cur = fake_conn.cursor()
fake_cur.copy_expert(copy_sql, dbcopy_f)
Run Code Online (Sandbox Code Playgroud)

sessionmaker不是必需的,但是如果你习惯于创建引擎和会话同时使用raw_connection你需要将它们分开(除非有某种方式通过会话对象访问引擎我不会知道).提供给copy_expert它的sql字符串也不是它的唯一方法,有一个基本copy_to函数,你可以使用你可以通过普通COPYTO查询的参数子集.对我来说命令的整体性能似乎很快,复制出约20000行的表.

http://initd.org/psycopg/docs/cursor.html#cursor.copy_to http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.raw_connection

  • 为我工作,但是我必须在最后做`fake_conn.commit()` (2认同)

dth*_*dor 18

如果您的引擎配置了psycopg2连接字符串(这是默认设置,或者是"postgresql://..."或者"postgresql+psycopg2://..."),您可以使用SQL Alchemy会话创建一个psycopg2游标

cursor = session.connection().connection.cursor()
Run Code Online (Sandbox Code Playgroud)

你可以用它来执行

cursor.copy_from(...)
Run Code Online (Sandbox Code Playgroud)

光标将在与您当前会话相同的事务中处于活动状态.如果a commit或者rollback发生了,抛出a的任何进一步使用光标psycopg2.InterfaceError,你将不得不创建一个新的.

  • 为展示如何使用传统会话实际获取光标而致谢。 (2认同)

swa*_*eck 12

看起来不像.

您可能只需使用psycopg2来公开此功能并放弃ORM功能.我想我在这样的操作中并没有真正看到ORM的好处,因为它是一个直接的批量插入并处理单个对象,而ORM实际上并没有太多意义.

  • 超级 - 可以通过engine.raw_connection()获取psycopg (5认同)

Fab*_*les 8

您可以使用:

def to_sql(engine, df, table, if_exists='fail', sep='\t', encoding='utf8'):
    # Create Table
    df[:0].to_sql(table, engine, if_exists=if_exists)

    # Prepare data
    output = cStringIO.StringIO()
    df.to_csv(output, sep=sep, header=False, encoding=encoding)
    output.seek(0)

    # Insert data
    connection = engine.raw_connection()
    cursor = connection.cursor()
    cursor.copy_from(output, table, sep=sep, null='')
    connection.commit()
    cursor.close()
Run Code Online (Sandbox Code Playgroud)

我在5秒而不是4分钟内插入200000行


ber*_*rio 5

您不需要下拉到 psycopg2,使用 raw_connection 或游标。

只需照常执行 sql,您甚至可以使用绑定参数text()

engine.execute(text('''copy some_table from :csv
                       delimiter ',' csv'''
                   ).execution_options(autocommit=True),
               csv='/tmp/a.csv')
Run Code Online (Sandbox Code Playgroud)

execution_options(autocommit=True)如果此 PR被接受,您可以删除

  • 不,链接为“此 PR”的不是我的存储库,它是 sqlalchemy 的正常/官方存储库。OTOH,PR 显然是我的,这不是秘密:我在 stackoverflow 和 bitbucket 上使用相同的用户名。无论如何,我在研究该更改的示例时偶然发现了这个问题,并且我所写的所有内容实际上都是正确的。我本可以避免链接 PR,但是(如果它被接受)那么这个答案将建议一个过时的片段,除非我或某人会记得事后更新它 (2认同)

Mic*_*oka 5

如果您从 SQLAlchemy 开始,您需要首先访问连接引擎(也可以通过bind某些 SQLAlchemy 对象的属性名称来了解):

engine = create_engine('postgresql+psycopg2://myuser:password@localhost/mydb')
# or 
engine = session.engine
# or any other way you know to get to the engine
Run Code Online (Sandbox Code Playgroud)

您可以从引擎中隔离 psycopg2 连接:

# get a psycopg2 connection
connection = engine.connect().connection

# get a cursor on that connection
cursor = connection.cursor()
Run Code Online (Sandbox Code Playgroud)

下面是针对该份声明与使用一些模板cursor.copy_expert(),一个更完整,更灵活的选择比copy_from()copy_to()因为它是在此间表示:https://www.psycopg.org/docs/cursor.html#cursor.copy_expert

# to dump to a file
dump_to = """
COPY mytable 
TO STDOUT
WITH (
    FORMAT CSV,
    DELIMITER ',',
    HEADER
);
"""

# to copy from a file:
copy_from = """
COPY mytable 
FROM STDIN
WITH (
    FORMAT CSV,
    DELIMITER ',',
    HEADER
);
"""
Run Code Online (Sandbox Code Playgroud)

查看上述选项的含义以及您的特定情况可能感兴趣的其他选项https://www.postgresql.org/docs/current/static/sql-copy.html

重要说明:指向文档的链接cursor.copy_expert()指示使用 STDOUT 写出到文件和使用 STDIN 从文件复制。但是,如果您查看 PostgreSQL 手册中的语法,您会注意到您还可以直接在 COPY 语句中指定要写入的文件或直接写入的文件。不要那样做,如果您不是以 root 身份运行,那么您可能只是在浪费时间(在开发过程中谁以 root 身份运行 Python?)只需按照 psycopg2 的文档中的说明进行操作cursor.copy_expert(),并在您的语句中指定 STDIN 或 STDOUT ,应该没问题。

# running the copy statement
with open('/path/to/your/data/file.csv') as f:
     cursor.copy_expert(copy_from, file=f)

# don't forget to commit the changes.
connection.commit()
Run Code Online (Sandbox Code Playgroud)