【问题标题】:creating a temporary table from a query using sqlalchemy orm使用 sqlalchemy orm 从查询创建临时表
【发布时间】:2012-03-24 12:23:39
【问题描述】:

我可以这样创建一个临时表:

session.execute("CREATE TABLE temptable SELECT existingtable.id, "
    "existingtable.column2 FROM existingtable WHERE existingtable.id<100000")

但新表不可读,因为它说它没有主键。 existingtable.id 是现有表的主键,所以我希望它在临时表中得到相同的处理。

但是,无论如何,我宁愿找到一些 ORM 方式来做到这一点。给定:

temp_table = Table('temptable', metadata, 
    Column('id', Integer, primary_key=True),
    Column('column2', Integer),
    useexisting=True )
class TempTable(object):
    pass
mapper(TempTable, temp_table)
temp_table.create(bind=session.bind, checkfirst=True)
if session.query(TempTable).delete(): #make sure it's empty
    session.commit()

如何在不执行 100000 session.query.add(TempTable(...)) 命令的情况下使用 existingtable 的某些选定内容填充 temp_table?或者有没有一种方法可以从类似于上面的普通 SQL 版本的查询中创建表?

【问题讨论】:

  • 只是古玩..如果您使用第一种方法创建临时表的定义,它会起作用吗?例如 create table tablename (id primarykey, column1) Insert into tablename select id, column2 from existing table where...
  • @AJP 是的,我认为这就是答案。不幸的是,没有相当于 INSERT INTO 的 SA ORM,而且我也没有简单的方法将相对复杂的查询编译成 sql 语句。

标签: python sql sqlalchemy


【解决方案1】:

这不完全是 ORM,但最初创建表时,我会克隆表结构(请参阅下面示例中的 cloneTable)。对于复制数据,我会使用InsertFromSelect example

编辑: 从 0.8.3 版开始,SqlAlchemy 支持Insert.from_select() 开箱即用。因此,下面示例中的 InsertFromSelect 类和相应的访问者可以直接替换,不再需要。由于历史原因,我保留原始示例不变。

这是一个工作示例

from sqlalchemy import Table
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import UpdateBase

class InsertFromSelect(UpdateBase):
    def __init__(self, table, select):
        self.table = table
        self.select = select

@compiles(InsertFromSelect)
def visit_insert_from_select(element, compiler, **kw):
    return "INSERT INTO %s %s" % (
        compiler.process(element.table, asfrom=True),
        compiler.process(element.select)
    )

def cloneTable(name, table, metadata):
    cols = [c.copy() for c in table.columns]
    constraints = [c.copy() for c in table.constraints]
    return Table(name, metadata, *(cols + constraints))

# test data
from sqlalchemy import MetaData, Column, Integer
from sqlalchemy.engine import create_engine
e = create_engine('sqlite://')
m = MetaData(e)
t = Table('t', m, Column('id', Integer, primary_key=True),
          Column('number', Integer))
t.create()
e.execute(t.insert().values(id=1, number=3))
e.execute(t.insert().values(id=9, number=-3))

# create temp table
temp = cloneTable('temp', t, m)
temp.create()

# copy data
ins = InsertFromSelect(temp, t.select().where(t.c.id>5))
e.execute(ins)

# print result
for r in e.execute(temp.select()):
    print(r)

【讨论】:

  • 不幸的是,运行此命令时出现导入错误:ImportError: cannot import name UpdateBase.使用 InsertFromSelect 示例的类似导入错误。我正在使用 SA 0.5.7
  • @Paul:啊,这个功能从 SA 0.6 开始才可用。我已经用 0.7.5 测试过了
  • 非常好的答案。我真的需要这个解决方案。我有这个问题要问你。 stackoverflow.com/questions/30575111/… 你的方法是最好的方法吗?就像先创建表然后从选择中插入?
  • @Ranjith:对于这种情况,我可能会创建自己的自定义 SQL 构造 SelectInto(类似于上面的 InsertFromSelect),它利用大多数 SQL 方言中的可用语法和 dialect-specific compilation rules (例如,SELECT * INTO NewTable FROM OldTable 用于 SQL Server,CREATE TABLE NewTable AS SELECT * FROM OldTable 用于 Oracle 或 SQLite)。您还可以查看物化视图 (Oracle) 或索引视图 (SQL Server)。
  • 究竟是什么让这张桌子成为临时的?不就是一张普通的桌子吗?如果您将表命名为“#temp”,那么它就是一个临时表。
猜你喜欢
  • 2022-11-22
  • 2020-07-20
  • 1970-01-01
  • 2014-08-03
  • 1970-01-01
  • 2023-03-18
  • 2020-05-10
  • 1970-01-01
  • 2013-12-03
相关资源
最近更新 更多