【发布时间】:2016-04-25 16:53:09
【问题描述】:
SQLAlchemy 的最大缺点似乎是在处理临时表时需要倒退几个步骤。例如,一个非常常见的用例是创建一个非常特定于一项任务的临时表,将一些数据放入其中,然后对其进行联接。
对于初学者来说,声明一个临时表是冗长且有限的。请注意,在此示例中,我必须对其进行编辑,因为我的类实际上继承了一个基类,所以我在这里给出的内容可能略有不正确。
@as_declarative(metaclass=MetaBase)
class MyTempTable(object):
__tablename__ = "temp"
__table_args__ = {'prefixes': ['TEMPORARY']}
id = Column(Integer(), primary_key=True)
person_id = Column(BigInteger())
a_string = Column(String(100))
创建它是不直观的:
MyTempTable.__table__.create(session.bind)
我还必须记住明确删除它,除非我做一些创造性的事情来让它通过 ON COMMIT DROP 呈现:
MyTempTable.__table__.drop(session.bind)
此外,除非临时表完成“顶级”,否则我刚刚给出的内容甚至都不起作用。我还没有完全弄清楚这一点(因为不想花时间调查它为什么不起作用),但基本上我尝试使用 session.begin_nested() 在嵌套事务中以这种方式创建一个临时表,而你最终得到一个错误,说关系不存在。但是,我有几种情况,我在嵌套事务中创建一个临时表以进行单元测试,它们工作得很好。检查回显输出,似乎区别在于一个在 BEGIN 语句之前呈现,而另一个在它之后呈现。这是使用 Postgresql。
在嵌套事务中起作用并且坦率地说可以为您节省大量时间的是,只需键入该死的 sql 并使用 session.execute 执行它。
session.execute(text(
"CREATE TEMPORARY TABLE temp ("
" id SERIAL,"
" person_id BIGINT,"
" a_string TEXT"
") ON COMMIT DROP;"
))
当然,如果你这样做,你仍然需要一个相应的表模型来使用 ORM 功能,或者必须坚持使用原始 sql 查询,这首先违背了 SQLAlchemy 的目的。
我想知道我是否在这里遗漏了一些东西,或者是否有人提出了一个更优雅的解决方案。
【问题讨论】:
-
是的,我通常只是直接使用 sql,但我不会说它违背了目的。
-
本页docs.sqlalchemy.org/en/latest/changelog/migration_10.html (#2891) 暗示可能有另一种创建临时表的方法
-
我有类似的问题,但调用
MyTempTable.__table__.create(session.connection())似乎可以解决我的工作流程中不存在的关系问题。见:stackoverflow.com/questions/15774899/… -
实际上,
MyTempTable.__table__.create(session.bind)似乎无法在会话中正常工作 - 看起来它在不同的连接中创建它,但session.execute(CreateTable(MyTempTable.__table__))按预期工作 -
session.bind将创建一个新连接。要重用会话连接,请使用session.connection()。另外,使用checkfirst=True,注意sqlalchemy 1.0之前的postgresql不兼容。所以,使用:MyTempTable.__table__.create(session.connection(), checkfirst=True)
标签: python postgresql sqlalchemy temp-tables