SQLAlchemy에서 OR 사용


191

문서를 살펴본 결과 SQLAlchemy에서 OR 쿼리를 수행하는 방법을 찾지 못하는 것 같습니다. 이 쿼리를 수행하고 싶습니다.

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

같은 것이어야합니다

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

답변:


322

로부터 튜토리얼 :

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

72
이 방법 지원 당신이 나에게 일의 긴 목록을 가지고 그렇다면, 발전기를 사용합니다, 당신은 할 수filter(or_(User.name == v for v in ('Alice', 'Bob', 'Carl')))
robru

66
@Robru의 조언은 불필요하게 비효율적입니다. 컬렉션이 이미 있으면 다음 in_과 같이 연산자를 사용해야합니다 .filter(User.name.in_(['Alice', 'Bob', 'Carl']))
intgr

5
아 고마워 sqlalchemy가 그 필터를 가지고 있다는 것을
몰랐다

8
@intgr LIKE 연산자와 같이 in_ 대신 다른 연산자를 사용하려는 경우 robru가 표시 한 예제가 여전히 효율적입니다.
Lhassan Baazzi

2
@intgr Oracle에 대한 나의 경험은 "OR"시퀀스가 "IN"을 사용하는 것보다 훨씬 빠르다는 것을 보여줍니다. 또한 "IN"은 ~ 1000 개의 항목으로 제한되지만 "OR"은 아닙니다.
ga

321

SQLAlchemy의는 비트 연산자를 오버로드 &, |그리고 ~그래서 대신 추한 어려운 읽기 접두사 구문 or_()and_()(에 같은 Bastien의 대답 ) 당신이이 연산자를 사용할 수 있습니다 :

.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호출을 사용하지 않고 첫 번째 사이 에 필터 인수를 사용할 수 있습니까?
체이스 샌드 만

21
@ChaseSandmann : 그렇습니다. 그러나 더 읽기 쉬울까요? No.
ThiefMaster

1
여기에 SQLAlchemy 문서에 대한 링크가 있으면 좋을 것입니다!
Cheche

@ThiefMaster 우연의 일치가 당신의 별칭에 도둑이 있고 당신의 예에서 Whitey Bulger가 있습니까?
TheRealChx101

35

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)

죄송합니다, 약간의 실수가 있습니다, chanhe 다음 줄 : chan = select ([tableobject]). where (and _ (* filterargs))
delpozov
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.