如何将许多“x和y”条件与OR结合用于WHERE子句

时间:2016-06-17 06:03:22

标签: python sqlalchemy

我有多对多的联结表,类似于以下内容:

        FooBar
-----------------------
id    | foo_id | bar_id
1     |    1   |    1
2     |    1   |    2
3     |    2   |    3
4     |    3   |    4

以及(foo_id, bar_id)的列表,例如:

items = [(1, 1), (1, 2), (2, 3), (3, 4)

如何在SQLAlachemy中执行以下查询?

SELECT id
FROM foo_bar
WHERE (foo_id = 1 AND bar_id = 1)
   OR (foo_id = 1 AND bar_id = 2)
   OR (foo_id = 2 AND bar_id = 3)
   OR (foo_id = 3 AND bat_id = 4)

我尝试了以下变体,但它们都返回一个仅包含ANDs

的WHERE子句
from sqlalchemy import and_, or_
q = session.query(FooBar)
for item in items:
    q = q.filter(or_(and_(FooBar.foo_id == item[0], FooBar.bar_id == item[1])))

print q.statement
for item in 

1 个答案:

答案 0 :(得分:2)

问题在于,使用单个表达式调用or_()基本上只是表达式,因为没有任何与OR有关。重复调用Query.filter()会附加与AND结合的新谓词。将迭代移到filter(or_())

中的项目上
q = q.filter(or_(*(and_(FooBar.foo_id == foo_id, FooBar.bar_id == bar_id)
                   for foo_id, bar_id in items)))

这将生成一个生成器表达式,然后将其解压缩为or_()的位置参数。

如果使用支持复合IN结构的后端,例如Postgresql和MySQL,则可以将其替换为tuple_().in_

from sqlalchemy import tuple_

...

q = q.filter(tuple_(FooBar.foo_id, FooBar.bar_id).in_(items))