SQLAlchemy临时表痛苦的解决方案?

Jam*_*son 10 python postgresql sqlalchemy temp-tables

似乎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))
Run Code Online (Sandbox Code Playgroud)

创建它是不直观的:

MyTempTable.__table__.create(session.bind)
Run Code Online (Sandbox Code Playgroud)

除非我做一些有创意的事情来使用ON COMMIT DROP进行渲染,否则我还必须记住明确删除它:

MyTempTable.__table__.drop(session.bind)
Run Code Online (Sandbox Code Playgroud)

而且,除非临时表完成"顶级",否则我刚刚给出的内容甚至不起作用.我还没有完全弄明白(因为不想花时间调查它为什么不起作用),但基本上我尝试使用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;"
        ))
Run Code Online (Sandbox Code Playgroud)

当然,如果你这样做,你仍然需要一个相应的表模型来使用ORM功能,或者必须坚持使用原始的SQL查询,这首先会破坏SQLAlchemy的目的.

我想知道我是否在这里遗漏了一些东西,或者有人提出了一个更优雅的解决方案.

Mup*_*sat 4

我将 ORM 与 Core 一起使用。ORM 保留用于更高级别的操作。对于大量数据和临时表,Core 更方便。例子:

temptbl_name = 'temp_del_dup_pk_{}'.format(datestamp)
temptbl = Table(temptbl_name, metadata, Column('col1', Integer, index=True),..., extend_existing=True)
temptbl.create(engine)
Run Code Online (Sandbox Code Playgroud)

更新 这是一个简单的函数,可以动态生成临时表 ORM 定义:

def temp_table(name, cols):
    args = dict(col1=Column(Integer, index=True),...)
    args['__tablename__'] = name
    args['__table_args__'] = dict(extend_existing=True)
    return type(name, (Base,), args)
Run Code Online (Sandbox Code Playgroud)

镜像现有表的列可能很有用:

def temp_table(name, base_table):
    args = {c.name:c.copy() for c in base_table.__table__.c}
    ...
Run Code Online (Sandbox Code Playgroud)