我正在使用PostgreSQL 9.3和SQLAlchemy 1.0.11
我的代码如下:
import sqlalchemy as sa
engine = sa.create_engine('postgresql+psycopg2://me@myhost/mydb')
conn = engine.connect()
metadata = sa.MetaData()
# Real table has more columns
mytable = sa.Table(
'my_temp_table', metadata,
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('something', sa.String(200)),
prefixes=['TEMPORARY'],
)
metadata.create_all(engine)
pg_conn = engine.raw_connection()
with pg_conn.cursor() as cursor:
cursor.copy_expert('''COPY my_temp_table (id, something)
FROM STDIN WITH CSV''',
open('somecsvfile', 'r'))
现在这很好用 - cursor.rowcount
报告插入的预期行数。我甚至可以运行cursor.execute('SELECT count(*) FROM my_temp_table'); print(cursor.fetchone())
,它会显示相同的#。问题是当我尝试从SQLAlchemy的连接运行查询时,例如
result = conn.execute(sa.text('SELECT count(*) FROM my_temp_table'))
我把它放在哪里都没关系。我试过几个地方:
cursor.close()
pg_conn.close()
似乎没有任何作用 - 无论我从哪里运行查询,它都是barfs:
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) relation "my_temp_table" does not exist
有趣的是,如果我将代码包装在try/except
中,那么我可以成功地在except块中执行cursor.execute(...)
。
实际上,现在我已经写出来了,似乎在任何地方使用sqlalchemy连接 都无法看到这些表存在。
那是什么给出的?为什么我的SQLAlchemy连接没有看到这些表,但postgres(engine.raw_connection()
)会这样做?
进一步揭开神秘面纱 - 如果我在 metadata.create_all(engine)
之后创建连接,它就可以了!嗯,有点。
我可以从表中进行选择,但是当我得到engine.raw_connection()
时它会在.copy_expert
上失败,因为它无法找到该表。
答案 0 :(得分:3)
首先要注意的是临时表只对创建它们的连接可见。
第二个是Engine
没有封装单个连接;它管理connection pool。
最后,documentation指出直接在Engine
(在他们的示例中为engine.execute("select ...")
)执行的操作将在内部获取并释放自己的连接。
考虑到所有这一切,很清楚你的例子中发生了什么:
conn = engine.connect()
从池中获取Connection#1。metadata.create_all(engine)
隐式获取Connection#2(因为引擎的角度来看,#1仍在“正在使用中”),使用它来创建表,然后将其释放回池中。pg_conn = engine.raw_connection()
再次获得#2,因此通过此对象执行的COPY
仍然可以看到该表。conn
仍在使用#1,您通过此对象执行的任何操作都无法查看您的临时表。在你的第二个案例中:
metadata.create_all(engine)
隐式获取/使用/发布Connection#1。conn = engine.connect()
获得#1并持有它。pg_conn = engine.raw_connection()
获取#2,COPY
无法找到临时表。故事的寓意:如果你正在做一些依赖于连接状态的事情,你最好确定你正在使用哪种连接。直接在engine
上运行命令对于独立操作来说很好,但是对于涉及临时表的任何事情,你应该获得一个连接并坚持每一步(包括创建表,我建议你改为{{1 }})。
答案 1 :(得分:0)
嗯,这不会回答为什么,但它是如何实现我想要的。
而不是:
pg_conn = engine.raw_connection()
with pg_conn.cursor() as cursor:
只需将其替换为:
with conn.connection.cursor() as cursor:
SQLAlchemy连接对象exposes its underlying DBAPI connection通过.connection
属性。无论涉及什么魔法都是正确的。