假設你有象下面這樣(簡化)模型:
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
s,這將產生基本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))
但是,如果存在具有兩個或兩個以上列表中的利益的事件,查詢將返回SAM e Event.name
多次。 query = session.query(Event.name.distinct())
版本2:您可以通過使用distinct
的工作,雖然,它周圍或者,您也可以做到這一點只用關係,這將使用子查詢與EXISTS
條款產生不同的SQL
,但語義應該是相同:
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()
人們可以agrue,這造成不是很漂亮的SQL語句,但這正是使用的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)
你確定你的'WHERE'子句檢查'event_to_interest.id'而不是'event_to_interest.interest_id'嗎? – van
@van,對。必須有'interest_id'。 –