在 SQLAlchemy 中使用 OR

Posted

技术标签:

【中文标题】在 SQLAlchemy 中使用 OR【英文标题】:Using OR in SQLAlchemy 【发布时间】:2011-12-18 01:23:18 【问题描述】:

我查看了through the docs,但似乎不知道如何在 SQLAlchemy 中进行 OR 查询。我只想做这个查询。

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

应该是这样的

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

【问题讨论】:

【参考方案1】:

来自tutorial:

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

【讨论】:

请注意,此方法支持使用生成器,因此如果您有很长的 OR 列表,您可以使用 filter(or_(User.name == v for v in ('Alice', 'Bob', 'Carl'))) @Robru 的建议不必要地低效。如果您已经有一个集合,那么您应该像这样使用in_ 运算符:filter(User.name.in_(['Alice', 'Bob', 'Carl'])) 啊,谢谢,我不知道 sqlalchemy 有那个过滤器 @intgr 如果您想使用其他运算符而不是 in_,例如 LIKE 运算符,robru 显示的示例仍然有效。 @intgr 我使用 Oracle 的经验表明,“OR”序列比使用“IN”要快得多。此外,“IN”仅限于一组约 1000 个条目,而“OR”则不是。【参考方案2】:

SQLAlchemy 重载了位运算符 &|~,因此您可以使用带有 or_()and_() 的丑陋且难以阅读的前缀语法(如 Bastien's answer)这些运算符:

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

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

所以您的整个查询可能如下所示:

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

【讨论】:

+1,但是您能否将最后两个过滤器参数包装在更多括号中,并在它们和第一个之间使用&(而不是使用第二个filter调用)以获得相同的效果? @ChaseSandmann:是的,你可以。但它会更具可读性吗?没有。【参考方案3】:

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))

【讨论】:

这可以与列上的== 运算符一起使用吗?我看到像,我喜欢等实现但没有“等于”,除了 __eq__ 覆盖显然只是返回一个布尔值,而不是我可以放入 or_() 的过滤器。 嗯,不,你不需要写这么复杂的逻辑。您始终可以将您的连词收集在一个临时变量中。 IE。而不是将它们收集在一个数组中,而是将一个变量设置为 False (最初)和|= 你的附加条件。【参考方案4】:

对于 SQLAlchemy ORM 2.0,|or_ 都被接受。

Documentation

from sqlalchemy.future import select
from sqlalchemy.sql import or_


query = select(User).where(or_(User.name == 'ed', User.name == 'wendy'))
print(query)

# also possible:

query = select(User).where((User.name == 'ed') | (User.name == 'wendy'))
print(query)

【讨论】:

【参考方案5】:

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

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)

【讨论】:

对不起,我犯了一个小错误,chanhe以下行:query = select([tableobject]).where(and_(*filterargs))

以上是关于在 SQLAlchemy 中使用 OR的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy模型中的进程字段(使用flask_sqlalchemy)

在 SQLAlchemy 中使用 OR

在 sqlalchemy 中使用 DATEADD

在烧瓶中使用 SqlAlchemy 模型

sqlalchemy在pythonweb中开发的使用(基于tornado的基础上)

python web开发-flask中使用sqlalchemy