8

Python支持链式比较1 < 2 < 3转换为(1 < 2) and (2 < 3).

我正在尝试使用 SQLAlchemy 进行 SQL 查询,如下所示:

results = session.query(Couple).filter(10 < Couple.NumOfResults < 20).all()

我得到的结果并不像预期的那样。我已经打开了引擎的echo=True关键字,而且确实 - 生成的 SQL 查询只包含两个比较之一。

我找不到任何明确说明这是禁止的文档。我假设如果 Python 支持这种类型的表达式,那么 SQLAlchemy 也应该支持它。

为什么这不起作用?我想到了一种可能的解决方案(在答案中共享),但很高兴听到其他意见。

4

2 回答 2

4

SQLAlchemy 不支持 Python 的链式比较。以下是作者 Michael Bayer 的官方原因:

不幸的是,从 python 的角度来看,这可能是不可能的。“x < y < z”的机制依赖于两个单独表达式的返回值。诸如“column < 5”之类的 SQLA 表达式返回一个 BinaryExpression 对象,该对象的计算结果为 True - 因此第二个表达式永远不会被调用,我们也永远没有机会检测表达式链。此外,需要检测表达式链并将其转换为 BETWEEN,因为 SQL 不支持链式比较运算符。不包括检测chains->BETWEEN 部分,要完成这项工作需要__nonzero__()根据比较运算符的方向来操作BinaryExpression 对象的值,以便强制进行两个比较。添加一个基本的__nonzero__()返回 False 的 BinaryExpression 说明当前代码库对它的容忍度非常差,至少需要将数十种“if x:”类型的检查转换为“if x is None:”,但可能会有更难解决的其他问题。对于外界来说,它可能会造成严重破坏。鉴于此处适当的 SQL 运算符是 BETWEEN ,可以从 between 运算符轻松访问,我不认为向后弯腰和混淆人们的水平是值得的,所以这是一个“不会修复”。

详见: https ://bitbucket.org/zzzeek/sqlalchemy/issues/1394/sql-expressions-dont-support-x-col-y

于 2016-10-14T19:04:29.820 回答
2

原因是 Python 实际上会评估类似于以下内容的内容:

_tmp = Couple.NumOfResults
(10 < _tmp and _tmp < 20)

SQLAlchemy 不支持该and运算符(应该使用该运算符and_)。因此,SQLAlchemy 中不允许进行链式比较。

在原始示例中,应改为编写以下代码:

results = session.query(Couple).filter(and_(10 < Couple.NumOfResults, 
                                            Couple.NumOfResults < 20)).all()
于 2012-09-12T15:17:24.860 回答