如何从 sqlalchemy 中的 select 语句创建一个新表?

Posted

技术标签:

【中文标题】如何从 sqlalchemy 中的 select 语句创建一个新表?【英文标题】:How to create a new table from select statement in sqlalchemy? 【发布时间】:2015-06-01 13:40:13 【问题描述】:

我正在使用 sqlalchemy 的核心功能来编写一些抽象层。层本身需要能够从 select 语句创建表。

示例代码:

metadata = MetaData(bind=engine)
table = Table(table_name, metadata, autoload=True, autoload_with=engine)
s = select(table).where(table.c.column_1 > 10)

现在我想做的是从上面的 select 语句创建一个新表。我该怎么做?

注意:我也在https://groups.google.com/forum/#!topic/sqlalchemy/lKDkX68fOqI 提出了这个问题。很抱歉交叉发布

我能想到的唯一方法是编译上面绑定了参数的 select 语句。手动构造SQL,然后创建表

例如:

sql = str(s.compile(dialect=postgresql.dialect(),
                    compile_kwargs="literal_binds": True
                    )
          )

create_tbl_sql = "CREATE TABLE 0 AS 2".format(new_table_name, sql)

connection.execute(create_tbl_sql)

当 datetime 对象涉及 where 条件时,文字绑定编译也很痛苦。几乎每当查询中存在无法序列化的内容时。我将不得不解决这个问题。

采用这种方法似乎并不干净。所以我问整个社区他们是否知道更好的东西。

【问题讨论】:

【参考方案1】:

通常我们会继承 DDLElement,但如果您想使用绑定参数,我们将留在 SQL 元素系统中:

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import ClauseElement, Executable


class CreateTableAs(Executable, ClauseElement):

    def __init__(self, name, query):
        self.name = name
        self.query = query


@compiles(CreateTableAs, "postgresql")
def _create_table_as(element, compiler, **kw):
    return "CREATE TABLE %s AS %s" % (
        element.name,
        compiler.process(element.query)
    )

if __name__ == '__main__':
    from sqlalchemy import Table, Column, Integer, \
        MetaData, create_engine, select

    m = MetaData()
    t = Table('t', m, Column('x', Integer), Column('y', Integer))

    e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
    c = e.connect()
    trans = c.begin()

    t.create(c)
    c.execute(
        t.insert(),
        ["x": 1, "y": 2, "x": 11, "y": 3]
    )

    s = select([t]).where(t.c.x > 10)

    c.execute(CreateTableAs('t2', s))

    assert c.execute("select x, y from t2").fetchall() == [(11, 3)]
    trans.rollback()

输出:

2015-06-01 11:42:55,982 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2015-06-01 11:42:55,982 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE t (
    x INTEGER, 
    y INTEGER
)


2015-06-01 11:42:55,982 INFO sqlalchemy.engine.base.Engine 
2015-06-01 11:42:55,985 INFO sqlalchemy.engine.base.Engine INSERT INTO t (x, y) VALUES (%(x)s, %(y)s)
2015-06-01 11:42:55,986 INFO sqlalchemy.engine.base.Engine ('y': 2, 'x': 1, 'y': 3, 'x': 11)
2015-06-01 11:42:55,988 INFO sqlalchemy.engine.base.Engine CREATE TABLE t2 AS SELECT t.x, t.y 
FROM t 
WHERE t.x > %(x_1)s
2015-06-01 11:42:55,988 INFO sqlalchemy.engine.base.Engine 'x_1': 10
2015-06-01 11:42:55,996 INFO sqlalchemy.engine.base.Engine select x, y from t2
2015-06-01 11:42:55,996 INFO sqlalchemy.engine.base.Engine 
2015-06-01 11:42:55,997 INFO sqlalchemy.engine.base.Engine ROLLBACK

【讨论】:

我对 sqlalchemy 编程还不是很精通。我要解决的问题是我想从 select 语句创建表。我不是特别想要绑定参数。我认为绑定参数和编译是将 SQL 语句作为字符串获取的方式。在继续之前,我将阅读 DDLElement。不过感谢您的解决方案。 令我惊讶的是,他们在模块中还没有这方面的内容。 是的,这里也一样...寻找简单的方法:创建表作为选择...现在所有这些东西......好吧?!

以上是关于如何从 sqlalchemy 中的 select 语句创建一个新表?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SqlAlchemy 上订购嵌套的 SQL SELECT

SQLAlchemy如何检查值是否在两列中的值之间?

如何在 sqlalchemy 中执行 LIKE 查询?

如何从sqlalchemy中的查询中获取列表[重复]

SELECT 中的多个联接

SQLAlchemy 仅从连接表中选择列