如何将列表绑定到sqlalchemy中自定义查询中的参数?

Ant*_*ong 24 python sqlalchemy

我出于性能原因使用这个sql

 sql_tmpl = """delete from Data where id_data in (:iddata) """
 params = {  
                    'iddata':[1, 2,3 4],
                    }
 # session is a session object from   sqlalchemy
 self.session.execute(text(sql_tmpl), params)     
Run Code Online (Sandbox Code Playgroud)

但是我得到了一个例外

NotSupportedError: (NotSupportedError) ('Python type list not supported.  param=1', 'HY097') 
Run Code Online (Sandbox Code Playgroud)

是否有任何解决方法可以允许我将列表绑定到'in'子句的参数?

dwa*_*son 18

一个旧问题的新答案,因为似乎某些基本功能已经改变,因为这个问题/接受的答案是第一次发布的(正如@vicvicvic在@ Gary的回答中提到的那样,但我觉得它应该是更好的可见性的答案) .

psycopg2现在支持类型自适应,它允许在列表中将列表传递给查询中的单个参数化值.这也适用于SQLAlchemy,至少对于postgresql数据库的原始SQL查询(我无法访问其他数据库类型,所以我不知道是否sqlalchemy会尊重其他数据库的这种约定,但我的倾向引用需要的是它会工作).

some_ids = [1, 2, 3, 4]
query = "SELECT * FROM my_table t WHERE t.id = ANY(:ids);"
conn.execute(sqlalchemy.text(query), ids=some_ids)
## runs just fine
Run Code Online (Sandbox Code Playgroud)

我发现没有包装器调用sqlalchemy.text,它给了一个ProgrammingError: syntax error at or near ":".


k26*_*6dr 14

使用元组而不是列表,并且不需要在查询中的参数两边加上括号:

sql_tmpl = "delete from Data where id_data in :iddata"
params = {  
   'iddata':(1, 2, 3, 4),
}
self.session.execute(text(sql_tmpl), params)     
Run Code Online (Sandbox Code Playgroud)


小智 8

尝试不使用括号 :iddata 这对我有用。

sql_tmpl = """delete from Data where id_data in :iddata """
Run Code Online (Sandbox Code Playgroud)

  • 工作正常,但参数必须是元组。不适用于列表。 (5认同)
  • 取决于所使用的 DB-API 驱动程序。 (2认同)

Jas*_*ani 8

解决此问题的新方法适用于任何数据库(不仅依赖于psycopg2的类型适应),它使用扩展的绑定参数:

sql_tmpl = """delete from Data where id_data in :iddata"""
params = { 'iddata': [1, 2, 3, 4], }
# session is a session object from sqlalchemy
t = text(sql_tmpl)
t = t.bindparams(bindparam('iddata', expanding=True))
self.session.execute(t, params)
Run Code Online (Sandbox Code Playgroud)

  • 为了帮助任何需要此导入的人: from sqlalchemy import text from sqlalchemy import bindparam (4认同)
  • @jnylen那是因为pymysql支持列表适配。扩展bindparams不仅仅适用于烘焙(缓存)查询,因为并非所有DB-API驱动程序都支持列表适应,在这种情况下,您必须手动将所需的占位符形成和格式化到查询中。在某些查询中,它的速度也明显更快,例如将一个巨大的列表传递给“in_()”:/sf/ask/4048077771/ (3认同)
  • 为什么我们必须在“self.session.execute(t, params)”这一行中包含“params”?我们不是已经在上一行绑定了它们吗?那么这条线有什么作用呢?`t = t.bindparams(bindparam('iddata',扩展= True))` (2认同)
  • @MadPhysicist `params` 具有需要添加到查询中的实际参数值。`bindparam('iddata',expanding=True)` 仅将键 `iddata` 标记为“待扩展”。 (2认同)