繁体   English   中英

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

[英]How can I bind a list to a parameter in a custom query in 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”子句的参数?

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 ":"给出ProgrammingError: syntax error at or near ":"

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

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

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

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

添加到dwanderson 的答案:使用 SQLAlchemy,您可以使用func方法将“any”函数添加到查询中。 这对我使用 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)

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

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

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

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

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

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

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

ids = [1000032, 1000048]
sql = 'SELECT CompNo, CompName, CompType FROM Component WHERE DeptID IN %(ids)s' % {"ids": tuple(ids)}
cursor.execute(sql)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM