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

时间:2012-11-02 06:27:11

标签: 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)     

但是我得到了一个例外

NotSupportedError: (NotSupportedError) ('Python type list not supported.  param=1', 'HY097') 

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

8 个答案:

答案 0 :(得分:13)

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

psycopg2现在支持type adaptation,除了其他功能外,它还允许将列表传递到查询中的单个参数化值。这也适用于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

我发现如果没有对sqlalchemy.text的包装调用,它会给出ProgrammingError: syntax error at or near ":"

答案 1 :(得分:3)

尝试没有周围的parens:iddata这一直在为我工作。

sql_tmpl = """delete from Data where id_data in :iddata """

答案 2 :(得分:2)

据我所知,没有一个sql引擎允许传入数组参数。 sqlalchemy处理此方法的方法是为数组中的每个项传入一个参数。

>>> from sqlalchemy.sql import table, column
>>> print(table('Data').delete(column('id_data').in_([5, 6, 7,])))
DELETE FROM "Data" WHERE id_data IN (:id_data_1, :id_data_2, :id_data_3)

如果您不使用sqlalchemy表达式构造,则需要手动执行此操作。

答案 3 :(得分:1)

您可以使用循环生成where子句,并使用**打破query.execute参数中的列表。这是一个例子:https://gist.github.com/pawl/555e5eecce77d4de0ada

答案 4 :(得分:1)

适用于任何数据库的新方法(不仅仅依赖于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)

答案 5 :(得分:1)

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

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

答案 6 :(得分:0)

添加到dwanderson的答案:使用SQLAalchemy,您可以使用func方法将“any”函数添加到查询中。这适用于我使用SQLAlchemy 1.0.9和Postgres DB。

通用示例:

from sqlalchemy import func

# some list
id_list = [1, 2, 3]

# assuming you have created a session
query = session.query(Table.user_name, Table.user_id).\
    filter(Table.user_id == func.any(id_list))

# one way of running the query
query.all()

您可以验证列表是作为单个参数传递的(而不是列表中每个对象的参数)。

print(query.statement)
  

SELECT user_id,user_name   从表   WHERE table.user_id = any(:any_1)

答案 7 :(得分:0)

在Microsoft SQL Server中,您可以使用表值参数来完成同样的事情。

SELECT * FROM table_name WHERE customer_id in (SELECT * FROM @MyTVP)

TVP当前仅受PyTDS支持,不支持PyODBC。如果您有SQLAlchemy的较新版本,Jason Damiani详述的expanding=True标志可能是执行此操作的最佳方法。但是TVP会在紧要关头。