Python SQLAlchemy使用IN子句替换原始SQL参数

Python SQLAlchemy使用IN子句替换原始SQL参数,python,sqlalchemy,Python,Sqlalchemy,我有一条SQL语句,从%s中id所在的栏中选择foo。我有一个整数列表,例如,[1,2,3],我想把它转换成一个SQL语句,看起来像从(1,2,3)中id所在的条中选择foo 我使用SQLAlchemy Core进行连接池,并使用多个值子句使一些插入更易于编写和维护。我更喜欢用原始SQL编写大多数查询 要在Pyscopg2中执行此操作,我需要执行cursor.execute('SELECT..WHERE in%s',(元组(my_列表))。然而,我无法在SQLAlchemy中实现这一点 engi

我有一条SQL语句,
从%s中id所在的栏中选择foo
。我有一个整数列表,例如,
[1,2,3]
,我想把它转换成一个SQL语句,看起来像
从(1,2,3)中id所在的条中选择foo

我使用SQLAlchemy Core进行连接池,并使用多个
子句使一些插入更易于编写和维护。我更喜欢用原始SQL编写大多数查询

要在Pyscopg2中执行此操作,我需要执行cursor.execute('SELECT..WHERE in%s',(元组(my_列表))。然而,我无法在SQLAlchemy中实现这一点

engine.execute('SELECT…WHERE IN%s',tuple(my_list))
引发异常:TypeError:在字符串格式化过程中并非所有参数都转换。如果我只传递列表,而不是包装在元组中,则会引发相同的异常

如果我使用像
engine.execute('SELECT…WHERE id IN:ids',ids=my_list)
这样的命名参数,我会得到一个
编程错误
异常,因为SQLAlchemy创建了不正确的SQL:
SELECT*FROM foo WHERE id IN:ids
(它不会将:ids值替换为我的变量)。如果我传递一个元组,就会引发同样的异常


如何在SQLAlchemy中使用原始SQL使用
WHERE IN()
子句?

这是一种只有某些DBAPI支持的不寻常的格式,因为它将项目的元组呈现为单个SQL表达式,包括呈现参数之间的逗号等,所以类似
的语句执行(“select*from table WHERE value IN%s”这样的语句,(somelist,)
在数据库级别展开为
从(1、2、3)中的值所在的表中选择*

SQLAlchemy不希望使用这种格式-它已经对传入参数进行了一些检查,因为它涉及将参数路由到DBAPI
execute()
executemany()
方法,并且还接受一些不同的样式,这种转换的结果是这里的元组变平了。您可以通过再添加一个元组,使元组通过此解析:

from sqlalchemy import create_engine

engine = create_engine("postgresql://scott:tiger@localhost/test", echo=True)

with engine.connect() as conn:
    trans = conn.begin()


    conn.execute("create table test (data integer)")
    conn.execute(
            "insert into test (data) values (%s)",
            [(1, ), (2, ), (3, ), (4, ), (5, )]
        )

    result = conn.execute(
                "select * from test where data in %s",
                (
                    ((1, 2, 3),),
                )
            )

    print result.fetchall()
上述样式仅适用于某些DBAPI。一个快速测试证实它适用于psycopg2和MySQLdb,但不适用于sqlite3。它与DBAPI用来向数据库发送绑定参数的底层系统有更多的关系;psycopg2和MySQLdb都执行Python字符串插值和它们自己的转义,但是像cx_oracle这样的系统将分别将参数传递给OCI,因此这种方法在这种情况下不起作用


SQLAlchemy当然在使用SQL表达式构造时提供了操作符,但这不适用于直字符串。

我使用SQLAlchemy 0.9.8、python 2.7、MySQL 5.X和MySQL python作为连接器,在这种情况下,需要一个元组。我的代码如下:

id_list = [1, 2, 3, 4, 5] # in most case we have an integer list or set
s = text('SELECT id, content FROM myTable WHERE id IN :id_list')
conn = engine.connect() # get a mysql connection
rs = conn.execute(s, id_list=tuple(id_list)).fetchall()

希望你一切顺利。

那太时髦了。不幸的是,在SQLA中IN()查询必须以这种笨拙的方式完成——这种模式是我用来限制应用程序中查询数量的常用模式。哦,好吧,谢谢你的帮助!绝大多数用户使用的是在任何后端都可以工作的uz()。上面的技术不是后端不可知的(也不能是后端不可知的,除非SQLA违背DBAPI的使用约定)?in()仅在生成API中有效。我一点也不担心后端不可知论。只要这对PostgreSQL有效,这就很尴尬,但已经足够了。提供导入将很有帮助