SQLAlchemyでORを使用する


189

私はドキュメントを調べましたが、SQLAlchemyでORクエリを実行する方法を見つけることができないようです。このクエリを実行したいだけです。

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

のようなものでなければなりません

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

回答:


321

チュートリアルから:

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

65
@Robruのアドバイスは不必要に非効率的です。すでにコレクションを持っているなら、あなたは使用する必要がありますin_。このように演算子をfilter(User.name.in_(['Alice', 'Bob', 'Carl']))
intgr

5
ああ、私はsqlalchemyにそのフィルターがあることを知らなかった
robru

8
@intgr robruが示した例は、LIKE演算子など、in_の代わりに別の演算子を使用する場合でも、依然として効率的です。
Lhassan Baazzi 2017

2
@intgr Oracleでの私の経験では、「OR」のシーケンスは「IN」を使用するよりもはるかに高速です。また、「IN」は〜1000エントリのセットに制限されていますが、「OR」は制限されていません。
GA

318

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ですが、最後の2つのフィルター引数をより多くの括弧で囲み、&それらの間に最初の(2番目のfilter呼び出しを使用するのではなく)を使用して同じ効果を得ることができますか?
チェイスサンドマン2013

21
@ChaseSandmann:はい、できます。しかし、それはもっと読みやすいでしょうか?いいえ
ThiefMaster 2013

1
SQLAlchemyのドキュメントへのリンクをここに用意しておくと便利です。
チェシュ

@ThiefMasterあなたのエイリアスに泥棒が含まれていて、あなたの例にWhitey Bulgerがいるのは偶然ですか?
TheRealChx101

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

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.