在SQLAlchemy中使用OR


190

我看了看文档,似乎无法找出如何在SQLAlchemy中进行OR查询。我只想执行此查询。

SELECT address FROM addressbook WHERE city='boston' AND (lastname='bulger' OR firstname='whitey')

应该是这样的

addr = session.query(AddressBook).filter(City == "boston").filter(????)

Answers:


322

教程

from sqlalchemy import or_
filter(or_(User.name == 'ed', User.name == 'wendy'))

72
请注意,此方法支持使用生成器,因此,如果要进行OR的事情很长,则可以执行filter(or_(User.name == v for v in ('Alice', 'Bob', 'Carl')))
robru 2015年

66
@Robru的建议不必要地效率低下。如果您已经有一个集合,则应使用这样的in_运算符:filter(User.name.in_(['Alice', 'Bob', 'Carl']))
intgr 2013年

5
啊,谢谢,我不知道
sqlalchemy

8
@intgr如果您想使用其他运算符代替in_,例如LIKE运算符,robru展示的示例仍然有效。
Lhassan Baazzi '17年

2
@intgr我在Oracle上的经验表明,序列“ OR”比使用“ IN”要快得多。同样,“ IN”仅限于一组〜1000个条目,而“ OR”则不受限制。
ga

319

SQLAlchemy的重载位运算符&|~因此而不是丑陋和难以读取的前缀语法与or_()and_()(像巴斯蒂安的答案),你可以使用这些运营商:

.filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey'))

请注意,由于按位运算符的优先级,括号不是可选的

因此,您的整个查询可能如下所示:

addr = session.query(AddressBook) \
    .filter(AddressBook.city == "boston") \
    .filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey'))

8
+1,但您是否可以将最后两个过滤器参数包装在更多括号中,并&在它们和第一个过滤器参数之间使用,filter以达到相同的效果?
Chase Sandmann

21
@ChaseSandmann:是的,您可以。但是会更具可读性吗?号
ThiefMaster

1
在这里有一个指向SQLAlchemy文档的链接会很棒!
Cheche

@ThiefMaster巧合,您的别名包含小偷并且您的示例中有Whitey Bulger?
TheRealChx101 '19

34

or_() 在未知数量的OR查询组件的情况下,该函数很有用。

例如,假设我们正在创建一个带有少量可选过滤器的REST服务,如果任何过滤器返回true,则该服务应返回记录。另一方面,如果未在请求中定义参数,则我们的查询不应更改。没有or_()功能,我们必须执行以下操作:

query = Book.query
if filter.title and filter.author:
    query = query.filter((Book.title.ilike(filter.title))|(Book.author.ilike(filter.author)))
else if filter.title:
    query = query.filter(Book.title.ilike(filter.title))
else if filter.author:
    query = query.filter(Book.author.ilike(filter.author))

通过or_()功能可以将其重写为:

query = Book.query
not_null_filters = []
if filter.title:
    not_null_filters.append(Book.title.ilike(filter.title))
if filter.author:
    not_null_filters.append(Book.author.ilike(filter.author))

if len(not_null_filters) > 0:
    query = query.filter(or_(*not_null_filters))

1
非常有用的答案
Ray Toal '18

3

这真的很有帮助。这是任何给定表的实现:

def sql_replace(self, tableobject, dictargs):

    #missing check of table object is valid
    primarykeys = [key.name for key in inspect(tableobject).primary_key]

    filterargs = []
    for primkeys in primarykeys:
        if dictargs[primkeys] is not None:
            filterargs.append(getattr(db.RT_eqmtvsdata, primkeys) == dictargs[primkeys])
        else:
            return

    query = select([db.RT_eqmtvsdata]).where(and_(*filterargs))

    if self.r_ExecuteAndErrorChk2(query)[primarykeys[0]] is not None:
        # update
        filter = and_(*filterargs)
        query = tableobject.__table__.update().values(dictargs).where(filter)
        return self.w_ExecuteAndErrorChk2(query)

    else:
        query = tableobject.__table__.insert().values(dictargs)
        return self.w_ExecuteAndErrorChk2(query)

# example usage
inrow = {'eqmtvs_id': eqmtvsid, 'datetime': dtime, 'param_id': paramid}

self.sql_replace(tableobject=db.RT_eqmtvsdata, dictargs=inrow)

抱歉,我犯了一个小错误,请执行以下操作:query = select([tableobject])。where(and _(* filterargs))
delpozov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.