Python 将临时表与SQLAlchemy一起使用

Python 将临时表与SQLAlchemy一起使用,python,sql-server,pandas,sqlalchemy,temp-tables,Python,Sql Server,Pandas,Sqlalchemy,Temp Tables,我正在尝试将临时表与SQLAlchemy一起使用,并将其与现有表连接起来。这就是我目前所拥有的 engine = db.get_engine(db.app, 'MY_DATABASE') df = pd.DataFrame({"id": [1, 2, 3], "value": [100, 200, 300], "date": [date.today(), date.today(), date.today()]}) temp_table = db.Table('#temp_table',

我正在尝试将临时表与SQLAlchemy一起使用,并将其与现有表连接起来。这就是我目前所拥有的

engine = db.get_engine(db.app, 'MY_DATABASE')
df = pd.DataFrame({"id": [1, 2, 3], "value": [100, 200, 300], "date": [date.today(), date.today(), date.today()]})
temp_table = db.Table('#temp_table',
                      db.Column('id', db.Integer),
                      db.Column('value', db.Integer),
                      db.Column('date', db.DateTime))
temp_table.create(engine)
df.to_sql(name='tempdb.dbo.#temp_table',
          con=engine,
          if_exists='append',
          index=False)
query = db.session.query(ExistingTable.id).join(temp_table, temp_table.c.id == ExistingTable.id)
out_df = pd.read_sql(query.statement, engine)
temp_table.drop(engine)
return out_df.to_dict('records')
这不会返回任何结果,因为to_sql没有运行的insert语句我认为这是因为它们是使用sp_prepexec运行的,但我不完全确定这一点

然后我试着写出SQL语句CREATE TABLE temp_TABLE…,INSERT INTO temp_TABLE…,从中选择[id]。。。然后运行pd.read\u sqlquery,引擎。我收到了错误信息

此结果对象不返回行。它已自动关闭

我想这是因为这个语句不仅仅是选择


如何解决这个问题两种解决方案都可以,尽管第一种方案更可取,因为它避免了硬编码SQL。明确地说,我无法修改现有数据库中的架构—这是一个供应商数据库。

您可以尝试使用另一种解决方案—进程键控表

进程键控表只是一个用作 临时表。要允许进程同时使用该表,请 表有一个额外的列来标识流程。最简单的方法 do this是全局变量@spid@@spid是SQL中的进程id 服务器

进程密钥的一种替代方法是使用GUID数据类型 唯一标识符


如果要插入临时表中的记录数很少/中等,一种可能是使用文字子查询或值CTE,而不是创建临时表

# MODEL
class ExistingTable(Base):
    __tablename__ = 'existing_table'
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String)
    # ...
还假设以下数据将插入临时表:

创建包含该数据的CTE或子查询:

stmts = [
    # @NOTE: optimization to reduce the size of the statement:
    # make type cast only for first row, for other rows DB engine will infer
    sa.select([
        sa.cast(sa.literal(i), sa.Integer).label("id"),
        sa.cast(sa.literal(v), sa.Integer).label("value"),
        sa.cast(sa.literal(d), sa.DateTime).label("date"),
    ]) if idx == 0 else
    sa.select([sa.literal(i), sa.literal(v), sa.literal(d)])  # no type cast

    for idx, (i, v, d) in enumerate(rows)
]
subquery = sa.union_all(*stmts)

# Choose one option below.
# I personally prefer B because one could reuse the CTE multiple times in the same query
# subquery = subquery.alias("temp_table")  # option A
subquery = subquery.cte(name="temp_table")  # option B
使用所需的联接和筛选器创建最终查询:

query = (
    session
    .query(ExistingTable.id)
    .join(subquery, subquery.c.id == ExistingTable.id)
    # .filter(subquery.c.date >= XXX_DATE)
)

# TEMP: Test result output
for res in query:
    print(res)    
最后,获取熊猫数据帧:

out_df = pd.read_sql(query.statement, engine)
result = out_df.to_dict('records')

现有表格中有记录吗?@AzatIbrakov是的。我实际上把它改成了一个左连接,并添加了temp_table.c.date来确定。我得到了日期列中没有的行。为什么日期列的类型是DateTime而不是date?@AzatIbrakov这只是一些测试代码。这张桌子有一个日期时间。我不认为这会对输出有任何影响,是吗?我在sqlite上测试了它,它会导致问题。你建议在tempdb中创建这个表吗?我认为无论哪种方式,它都会遇到与我在问题的第二部分中遇到的问题相同的问题,即read_sql不返回任何行。此表应该在您的db my_数据库中创建,而不是在临时数据库中创建。这不是一个好方法,但它应该可以工作。我没有权限在那个数据库中创建表。这是一个供应商数据库。哈,我只是想在今天早上上下班的路上做这个。我将试一试并让您知道。从性能角度看,这个解决方案有多好?联盟对我来说真的很沉重。。。需要测试它,但如果有一些关于性能的想法,那就太棒了。。。
out_df = pd.read_sql(query.statement, engine)
result = out_df.to_dict('records')