22

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

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

有没有办法从 SQLAlchemy 访问这个功能?

4

6 回答 6

36

接受的答案是正确的,但如果您想要的不仅仅是 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)

不是必需的sessionmaker,但如果您习惯同时创建引擎和会话以使用raw_connection,则需要将它们分开(除非有某种方法可以通过会话对象访问引擎,而我没有'不知道)。提供给的 sql 字符串copy_expert也不是唯一的方法,有一个基本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

于 2014-02-27T16:33:52.363 回答
25

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

cursor = session.connection().connection.cursor()

您可以使用它来执行

cursor.copy_from(...)

光标将在与您当前会话相同的事务中处于活动状态。如果 a commitorrollback发生,任何进一步使用 throw a 的游标psycopg2.InterfaceError,您都必须创建一个新的。

于 2014-06-17T15:28:39.690 回答
13

您可以使用:

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

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

于 2017-05-25T13:19:45.747 回答
12

看起来不像

您可能只需要使用 psycopg2 来公开此功能并放弃 ORM 功能。我想我并没有真正看到 ORM 在这样的操作中的好处,因为它是直接的批量插入,并且处理单个对象(例如 ORM)并没有真正的意义。

于 2012-10-29T16:10:50.120 回答
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

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

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

# get a cursor on that connection
cursor = connection.cursor()

以下是用于 COPY 语句的一些模板,这是一个比此处指示cursor.copy_expert()的更完整和更灵活的选项: https ://www.psycopg.org/docs/cursor.html#cursor.copy_expert 。copy_from()copy_to()

# 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
);
"""

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

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

# 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()
于 2017-12-21T02:24:07.620 回答
4

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

像往常一样执行sql,你甚至可以使用绑定参数text()

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

execution_options(autocommit=True)如果此 PR将被接受,您可以放弃

于 2015-12-19T20:27:06.160 回答