2014-02-17 4 views
0

사용자, 관심 분야 및 이벤트가 있습니다. 사용자는 (다 대다) 관심사를 가지고 있습니다. 이벤트에는 (다 대다) 관심사가 있습니다. 그래서 "user_to_interest"와 "event_to_interest"라는 두 개의 "중간"테이블이 있습니다.SQLAlchemy : [..] (다 대다)에 태그가있는 모든 게시물 선택

사용자 관심 분야 목록에서 관심사가있는 모든 이벤트 (즉, [1, 144, 4324] 태그가있는 모든 이벤트)를 원하는대로 선택하려고합니다.

SELECT DISTINCT event.name FROM event JOIN event_to_interest ON event.id = event_to_interest.event_id WHERE event_to_interest.interest_id IN (10, 144, 432)

가 어떻게 SQLAlchemy의를 통해 그렇게해야합니다

SQL에서 나는 ~ 이런 것을 할 거라고?

+0

'WHERE' 절이'event_to_interest.interest_id'가 아닌'event_to_interest.id'를 확인하고 있습니까? – van

+0

@van, 맞아. 'interest_id'가 있어야합니다. –

답변

3

(필요한 경우 내가 플라스크-SQLAlchemy의를 사용하고 있습니다) 당신은 (간체) 모델을 아래와 같이 가지고 가정 :

user_to_interest = Table('user_to_interest', Base.metadata, 
    Column('id', Integer, primary_key=True), 
    Column('user_id', Integer, ForeignKey('user.id')), 
    Column('interest_id', Integer, ForeignKey('interest.id')) 
    ) 

event_to_interest = Table('event_to_interest', Base.metadata, 
    Column('id', Integer, primary_key=True), 
    Column('event_id', Integer, ForeignKey('event.id')), 
    Column('interest_id', Integer, ForeignKey('interest.id')) 
    ) 

class User(Base): 
    __tablename__ = 'user' 
    id = Column(Integer, primary_key=True) 
    name = Column(String) 

class Event(Base): 
    __tablename__ = 'event' 
    id = Column(Integer, primary_key=True) 
    name = Column(String) 

class Interest(Base): 
    __tablename__ = 'interest' 
    id = Column(Integer, primary_key=True) 
    name = Column(String) 

    users = relationship(User, secondary=user_to_interest, backref="interests") 
    events = relationship(Event, secondary=event_to_interest, backref="interests") 

버전-1 : 당신이 목록에 간단한 쿼리를 할 수 있어야 생성 interest_id들, 기본적으로 SQL 문이 당신이 원하는 :

interest_ids = [10, 144, 432] 
query = session.query(Event.name) 
query = query.join(event_to_interest, event_to_interest.c.event_id == Event.id) 
query = query.filter(event_to_interest.c.interest_id.in_(interest_ids)) 

그러나 두 목록에서 관심을 더 가지고 이벤트가있는 경우, 쿼리는 샘을 반환합니다 e Event.name 여러 번. EXISTS 절을 하위 쿼리를 사용하여 다른 SQL를 생성하는 또는, 당신은 단지 관계를 사용하여이 작업을 수행 할 수 있지만, 의미가 있어야한다 : query = session.query(Event.name.distinct())

버전-2 :하지만 distinct를 사용하여 주위-작업 할 수 있습니다 동일 :

query = session.query(Event.name) 
query = query.filter(Event.interests.any(Interest.id.in_(interest_ids))) 

이 버전은 중복에는 문제가 없습니다.

그러나, 나는 한 단계 뒤로 이동하고 특정 사용자에 대한 interest_ids을받을 수 있나요 가정 및 user_id (또는 User.id)

최종 버전 작동 쿼리를 생성 할 것입니다 : 두 번 any을 사용하여 :

def get_events_for_user(user_id): 
    #query = session.query(Event.name) 
    query = session.query(Event) # @note: I assume name is not enough 
    query = query.filter(Event.interests.any(Interest.users.any(User.id == user_id))) 
    return query.all() 

하나는이 그리 아름다운 SQL 문을 생성하는 agrue 수 있지만, 이것은 정확하게 구현 세부 사항을 숨 깁니다 SQLAlchemy의 사용의 아름다움이다.


보너스 : 더 많은 중복 관심을 가지고 이벤트에 더 높은 우선 순위를 부여 할 사실 수 있습니다. 이 경우에 도움이 될 수 있습니다 :

query = session.query(Event, func.count('*').label("num_interests")) 
query = query.join(Interest, Event.interests) 
query = query.join(User, Interest.users) 
query = query.filter(User.id == user_id) 
query = query.group_by(Event) 
# first order by overlaping interests, then also by event.date 
query = query.order_by(func.count('*').label("num_interests").desc()) 
#query = query.order_by(Event.date) 
+0

와우! 그런 상세한 답변을 주셔서 대단히 감사합니다! 당신은 진정한 SQL - alchemic이어야합니다 :) –

+0

당신은 단지 내 하루를 저장했습니다, 감사합니다! – ncrocfer