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クエリには2つの比較のうちの1つしか含まれていませんでした。

これが禁止されていることを明示的に示しているドキュメントが見つかりません。このタイプの式がPythonでサポートされている場合は、SQLAlchemyでもサポートされるはずだと思いました。

なぜこれが機能しないのですか?私は1つの可能な解決策を念頭に置いています(回答で共有されています)が、他の意見を聞いて喜んでいます。

4

2 に答える 2

4

SQLAlchemy は、Python の連鎖比較をサポートしません。著者のマイケル・ベイヤーによる公式の理由は次のとおりです。

残念ながら、これは Python の観点からはおそらく不可能です。「x < y < z」のメカニズムは、2 つの個別の式の戻り値に依存しています。"column < 5" などの SQLA 式は、True として評価される BinaryExpression オブジェクトを返します。したがって、2 番目の式が呼び出されることはなく、式のチェーンを検出する機会が与えられることはありません。さらに、SQL は連鎖比較演算子をサポートしていないため、式の連鎖を検出して BETWEEN に変換する必要があります。__nonzero__()チェーンの検出を含まない-> BETWEEN 部分、これを機能させるには、比較演算子の方向に基づいて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)

このand演算子は SQLAlchemy ではサポートされていません (and_代わりに使用する必要があります)。したがって、連鎖比較は SQLAlchemy では許可されていません。

元の例では、代わりに次のコードを書く必要があります。

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