Menggunakan ATAU dalam SQLAlchemy

191

Saya telah melihat -lihat dokumen dan sepertinya saya tidak bisa menemukan cara melakukan kueri ATAU dalam SQLAlchemy. Saya hanya ingin melakukan kueri ini.

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

Seharusnya seperti itu

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

Jawaban:

322

Dari tutorial :

from sqlalchemy import or_
filter(or_(User.name == 'ed', User.name == 'wendy'))
Bastien Léonard
sumber
72
Perhatikan bahwa pendekatan ini mendukung penggunaan generator, jadi jika Anda memiliki daftar panjang hal-hal untuk ATAU, Anda dapat melakukannyafilter(or_(User.name == v for v in ('Alice', 'Bob', 'Carl')))
robru
66
@ Nasihat Robru tidak perlu tidak efisien. Jika Anda sudah memiliki koleksi maka Anda harus menggunakan in_operator seperti ini:filter(User.name.in_(['Alice', 'Bob', 'Carl']))
intgr
5
Ah terima kasih saya tidak sadar sqlalchemy memiliki filter itu
robru
8
@intgr Contoh yang ditunjukkan oleh robru masih efisien, jika Anda ingin menggunakan operator lain alih-alih in_, misalnya operator LIKE.
Lhassan Baazzi
2
@intgr Pengalaman saya dengan Oracle menunjukkan bahwa urutan "OR" jauh lebih cepat daripada menggunakan "IN". Juga "IN" terbatas pada satu set ~ 1000 entri, sementara "OR" tidak.
ga
321

SQLAlchemy membebani operator bitwise &, |dan ~alih-alih sintaks awalan yang jelek dan sulit dibaca dengan or_()dan and_()(seperti dalam jawaban Bastien ) Anda dapat menggunakan operator ini:

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

Perhatikan bahwa tanda kurung tidak opsional karena didahulukan dari operator bitwise.

Jadi seluruh permintaan Anda dapat terlihat seperti ini:

addr = session.query(AddressBook) \
    .filter(AddressBook.city == "boston") \
    .filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey'))
Pencuri
sumber
8
+1, tetapi bisakah Anda membungkus dua argumen filter terakhir dalam lebih banyak tanda kurung dan menggunakan &antara mereka dan yang pertama (daripada menggunakan filterpanggilan kedua ) untuk efek yang sama?
Chase Sandmann
21
@ ChaseSandmann: Ya, Anda bisa. Tetapi apakah itu lebih mudah dibaca? Tidak.
ThiefMaster
1
Akan lebih baik untuk memiliki tautan ke dokumen SQLAlchemy di sini sebagai jawaban!
Cheche
@ThiefMaster Kebetulan bahwa alias Anda mengandung pencuri dan Anda memiliki Whitey Bulger dalam contoh Anda?
TheRealChx101
36

or_() fungsi dapat berguna jika ada jumlah komponen permintaan OR yang tidak diketahui.

Misalnya, mari kita asumsikan bahwa kita membuat layanan REST dengan beberapa filter opsional, yang akan mengembalikan catatan jika ada filter yang mengembalikan true. Di sisi lain, jika parameter tidak didefinisikan dalam permintaan, permintaan kami tidak boleh berubah. Tanpa or_()fungsi kita harus melakukan sesuatu seperti ini:

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

Dengan or_()fungsi itu dapat ditulis ulang untuk:

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))
Valar
sumber
1
Jawaban yang sangat membantu
Ray Toal
3

Ini sangat membantu. Ini implementasi saya untuk tabel apa saja:

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)
delpozov
sumber
Maaf saya membuat kesalahan kecil, chanhe baris berikut: query = select ([tableobject]). Di mana (dan _ (* filterargs))
delpozov