Sử dụng OR trong SQLAlchemy


189

Tôi đã xem qua các tài liệu và dường như tôi không thể tìm ra cách thực hiện truy vấn OR trong SQLAlchemy. Tôi chỉ muốn làm truy vấn này.

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

Nên là một cái gì đó như

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

Câu trả lời:


321

Từ hướng dẫn :

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

72
Lưu ý rằng phương pháp này hỗ trợ sử dụng máy phát điện, vì vậy nếu bạn có một danh sách dài những điều cần HOẶC, bạn có thể thực hiệnfilter(or_(User.name == v for v in ('Alice', 'Bob', 'Carl')))
robru 26/8/2015

65
Lời khuyên của @ Robru là không hiệu quả. Nếu bạn đã có một bộ sưu tập thì bạn nên sử dụng in_toán tử như thế này:filter(User.name.in_(['Alice', 'Bob', 'Carl']))
intgr

5
À cảm ơn tôi không biết sqlalchemy có bộ lọc đó
robru

8
@intgr Ví dụ được hiển thị bởi robru vẫn hiệu quả, nếu bạn muốn sử dụng toán tử khác thay vì in_, ví dụ toán tử THÍCH.
Lhassan Baazzi

2
@intgr Kinh nghiệm của tôi với Oracle cho thấy một chuỗi "HOẶC" nhanh hơn nhiều so với sử dụng "IN". Ngoài ra "IN" được giới hạn trong một bộ ~ 1000 mục, trong khi "HOẶC" thì không.
ga

318

SQLAlchemy làm quá tải các toán tử bitwise &, |~vì vậy thay vì cú pháp tiền tố xấu và khó đọc với or_()and_()(như trong câu trả lời của Bastien ), bạn có thể sử dụng các toán tử này:

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

Lưu ý rằng dấu ngoặc đơn không phảitùy chọn do sự ưu tiên của các toán tử bitwise.

Vì vậy, toàn bộ truy vấn của bạn có thể trông như thế này:

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

8
+1, nhưng thay vào đó, bạn có thể bọc hai đối số bộ lọc cuối cùng trong nhiều dấu ngoặc đơn hơn và sử dụng một &giữa chúng và đầu tiên (thay vì sử dụng filtercuộc gọi thứ hai ) cho cùng một hiệu ứng không?
Chase Sandmann

21
@ChaseSandmann: Có bạn có thể. Nhưng nó sẽ dễ đọc hơn? Số
ThiefMaster

1
Sẽ rất tuyệt khi có một liên kết đến các tài liệu SQLAlchemy ở đây để trả lời!
Cheche

@ThiefMaster Trùng hợp rằng bí danh của bạn chứa kẻ trộm và bạn có Whitey Bulger trong ví dụ của bạn?
TheRealChx101

34

or_() Hàm có thể hữu ích trong trường hợp không biết số lượng thành phần truy vấn OR.

Ví dụ: giả sử rằng chúng tôi đang tạo một dịch vụ REST với một vài bộ lọc tùy chọn, sẽ trả về bản ghi nếu bất kỳ bộ lọc nào trả về đúng. Mặt khác, nếu tham số không được xác định trong yêu cầu, truy vấn của chúng tôi không nên thay đổi. Không có or_()chức năng, chúng ta phải làm một cái gì đó như thế này:

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

Với or_()chức năng, nó có thể được viết lại thành:

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
Câu trả lời rất hữu ích
Ray Toal

3

Điều này đã thực sự hữu ích. Đây là cách triển khai của tôi cho bất kỳ bảng đã cho nào:

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)

Xin lỗi tôi đã mắc một lỗi nhỏ, chanhe dòng sau: query = select ([tableobject]). Trong đó (và _ (* bộ lọc))
delpozov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.