47

出于性能原因,我使用此 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”子句的参数?

4

9 回答 9

36

一种适用于任何数据库(不仅依赖于 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)
于 2019-05-30T17:20:54.493 回答
34

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

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

于 2016-09-09T14:45:22.200 回答
9

试试不带括号的,:iddata. 这一直对我有用。

sql_tmpl = """delete from Data where id_data in :iddata """
于 2014-07-15T07:50:36.123 回答
3

据我所知,没有一个 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 表达式构造,则需要手动执行此操作。

于 2012-11-02T10:04:10.197 回答
3

添加到dwanderson 的答案:使用 SQLAlchemy,您可以使用func方法将“任何”函数添加到查询中。这适用于我使用 SQLAlchemy 1.0.9 和 PostgreSQL 数据库。

通用示例:

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 FROM table WHERE table.user_id = any(:any_1)

于 2017-03-04T03:25:49.610 回答
3

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

sql_tmpl = "delete from Data where id_data in :iddata"
params = {  
   'iddata':(1, 2, 3, 4),
}
self.session.execute(text(sql_tmpl), params)     
于 2020-07-26T18:40:54.257 回答
0

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

于 2014-08-06T18:56:32.083 回答
0

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

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

TVP 目前仅支持PyTDS,不支持 PyODBC。如果您有较新版本的 SQLAlchemy ,Jason Damiani 详细介绍expanding=True标志可能是最好的方法。但TVP会在紧要关头做。

于 2019-07-10T16:07:22.157 回答
-2

如果您正在处理原始 SQL,则可以使用以下方法:

ids = [1000032, 1000048]
sql = 'SELECT CompNo, CompName, CompType FROM Component WHERE DeptID IN %(ids)s' % {"ids": tuple(ids)}
cursor.execute(sql)
于 2021-10-06T07:51:03.837 回答