2014-09-16 1 views
0

다 - 대 - 다 관계에서 JOIN을 수행 할 때 ON 절을 동적 필터로 확장 할 수 있습니까?SQLAlchemy : 다 대다 관계에서 LEFT JOIN을 수행 할 때 복잡한 ON 절

StackOverflow와 관련된 좋은 질문을 발견했습니다 : "Performing a left join across a many-to-many table with conditions". 불행히도 그 질문은 원시 SQL에 관한 것이며 단지 같은 문제를 설명합니다. SQLAlchemy에서 이것을 구현하는 방법을 찾지 못했습니다.

자, 환경을 설명하겠습니다.

Model = declarative_base() 

M2M = Table('m2m', Model.metadata, 
      Column('book_id', Integer, ForeignKey(...)), 
      Column('author_id', Integer, ForeignKey(...)), 

class Book(Model): 
    __tablename__ = 'books' 
    id = Column(Integer, primary_key=True, autoincrement=True) 
    authors = relation('Author', 
         secondary=M2M, 
         back_populates='books') 

class Author(Model): 
    __tablename__ = 'authors' 
    id = Column(Integer, primary_key=True, autoincrement=True) 
    books = relation('Book', 
        secondary=M2M, 
        back_populates='authors') 

이의 그들에게 책을 몇몇 저자를 만든 다음 할당 할 수 있습니다 :

A1 = Author() # id: 1 
A2 = Author() # id: 2 
A3 = Author() # id: 3 

B1 = Book(authors=[A1, A2]) # id: 1 
B2 = Book(authors=[A2])  # id: 2 
B3 = Book(authors=[A3])  # id: 3 

글쎄, 지금은 [1,3]에서 IDS outerjoined 저자와 책을 얻으려면 두 개의 테이블이있는 가정 [1, 2]에있는 ID들과 함께. 나는 Author ID가 일종의 "allowed-ids"목록 인 경우로드 된 Author로 Books B1과 B2를 얻고 싶습니다. 이러한 허용 된 ID 목록은 외부 코드에 의해 만들어 지므로 primaryjoin 또는 secondaryjoin 관계 필터를 만들 때 사용할 수 없으며 동적으로 허용 된 ID 목록이 생성됩니다.

this question에 따르면, 다음 쿼리는 도움이 될 것이다 :

SELECT books.id, authors.id 
FROM books 
LEFT JOIN m2m ON (
    books.id = m2m.book_id 
    AND m2m.author_id IN (1,2)) -- allowed author ids! 
LEFT JOIN authors ON author.id = m2m.author_id 
WHERE books.id IN (1,3) -- and any another filter 
; 

-- result: 
-- books.id | authors.id 
-- ---------+----------- 
--   1 |   1 
--   1 |   2 
--   3 |  null 

하지만 SQLAlchemy의를 사용하여 같은 쿼리를 작성하는 방법을 모르겠어요. 이 설명서에서는 하위 쿼리만을 기반으로하는 솔루션에 대해 설명합니다.

어떤 도움을 주셔서 감사합니다.

답변

0
book_ids = [1, 3] 
author_ids = [1, 2] 

q = (session.query(Book.id, Author.id) 
    .outerjoin(M2M, and_(Book.id == M2M.c.book_id, M2M.c.author_id.in_(author_ids))) 
    .outerjoin(Author, M2M.c.author_id == Author.id) 
    .filter(Book.id.in_(book_ids)) 
    ) 

그러나, 나는 아래 하나 JOIN 적은 비용으로 동일한 결과를 생성해야한다고 생각 :

q = (session.query(Book.id, M2M.c.author_id) 
    .outerjoin(M2M, and_(Book.id == M2M.c.book_id, M2M.c.author_id.in_(author_ids))) 
    .filter(Book.id.in_(book_ids)) 
    ) 
+0

가 대단히 감사합니다, 그것을 작동합니다! –