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

标签 python sqlalchemy

我有一个 SQL 语句,SELECT foo FROM bar WHERE id IN %s。我有一个整数列表,例如[1, 2, 3] 我希望它能变成一个 SQL 语句,看起来像 SELECT foo FROM bar WHERE id IN (1, 2, 3).

我将 SQLAlchemy Core 用于其连接池,并使一些具有多个 VALUES 子句的插入更易于编写和维护。我更喜欢用原始 SQL 编写我的大部分查询。

要在 Pyscopg2 中执行此操作,我执行 cursor.execute('SELECT .. WHERE IN %s', (tuple(my_list),))。但是,我无法在 SQLAlchemy 中完成这项工作。

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

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

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

最佳答案

这是一种仅由某些 DBAPI 支持的不寻常格式,因为它将项目的元组呈现为单独的 SQL 表达式,包括它呈现参数之间的逗号等,因此像 execute("select * from table where value in %s", (somelist, )) 这样的语句在数据库级别扩展为 select * from table where value in (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 用于将绑定(bind)参数发送到数据库的底层系统有更多关系; psycopg2 和 MySQLdb 都进行 Python 字符串插值和它们自己的转义,但是像 cx_oracle 这样的系统会将参数单独传递给 OCI,所以这种事情在那种情况下是行不通的。

SQLAlchemy 当然提供了 in_()使用 SQL 表达式构造时的运算符,但这不适用于直接字符串。

关于python - 使用 IN 子句替换 SQLAlchemy 原始 SQL 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14512228/

相关文章:

python - 如何使用连接模块运行 PyQt 应用程序?

python - QComboBox 忽略键盘输入

python - 使用 Tornado httpclient 对 Github API 的简单未授权请求返回 Forbidden

python - .one() 和 .first() 有什么区别

python - SQLAlchemy:从 db.Model 获取关系

python - 将成绩的连续值转换为类别

python - 是否有智能解决方案通过函数转换 DataFrame 并将结果设置到每个单元格?

python - 如何在 sqlalchemy 中根据子级长度查询父级

python - 分析 SQL 查询

mysql - 在 Python 3 中通过 SQLAlchemy 缓慢插入 Cloud SQL