SQL-l'Alchimie de requête de jointure - le moyen le plus efficace de requête
-
02-01-2020 - |
Question
Je suis en train de générer une requête et d'avoir de la difficulté à trouver le moyen le plus efficace de le faire dans sqlalchemy, (à noter que je suis en utilisant flacon-sqlalchemy)
Le but est de trouver tous les utilisateurs d'avoir une réunion avec un utilisateur spécifique.
Donc, disons que Frank a 10 réunions à venir, je veux générer une liste de toutes les personnes frank a une rencontre avec.
Voici mes modèles:
class UserMeeting(db.Model):
""" Associative table, links meetings to users in a many to many fashion"""
__tablename__ = 'userMeeting'
id = db.Column(db.Integer, primary_key = True)
meeting_id = db.Column(db.Integer, db.ForeignKey('meeting.id'), primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
class Meeting(db.Model):
__tablename__ = "meeting"
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(128))
#... other columns
#associative reference
attendees = db.relationship('UserMeeting', backref='meeting')
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key = True)
email = db.Column(db.String(128), index=True, unique=True)
password = db.Column(db.String(128))
#associative reference
attendingMeetings = db.relationship("UserMeeting", backref="user", cascade="all, delete-orphan")
Voici ce que j'ai essayé:
#Assume frank's a user with id == 1
frank = User.query.get(1)
franks_meetings = Meeting.query.join(Meeting.attendees).filter(UserMeeting.user == frank).all()
#not efficient way of getting users in meetings with frank
users = []
for meeting in franks_meetings:
for userMeeting in meeting.attendees:
if userMeeting.user != frank:
users.append(userMeeting.user)
#is there a way to just generate one query and get this data?
Je semble être manquant comment je pourrais simplement utiliser des jointures pour obtenir ces données.Toute aide serait appréciée!
La solution
Vous avez besoin de joindre le UserMeeting table avec elle-même, à l'aide de meeting_id comme la clé de jointure.Vous devrez peut-être l'alias de la table afin de faire référence à deux reprises.Je ne sais pas si je peux le type de la sqlalchemy syntaxe sur le haut de ma tête, mais le sql ressemble à:
select distinct(b.user_id) as other_user_id
from usermeeting a
inner join usermeeting b
on a.meeting_id=b.meeting_id
where a.user_id=1 and b.user_id != 1;
Et 1
est Frank.
Oh, et d'obtenir les détails de l'utilisateur aussi.Probablement, vous pourriez vous retrouver avec User
les objets directement à partir de le faire dans sqlalchemy:
select distinct(u.id), u.email
from usermeeting a
inner join usermeeting b
on a.meeting_id=b.meeting_id
inner join users u
on b.user_id=u.id
where a.user_id=1 and b.user_id != 1;
Autres conseils
Voici la version SQLalchemy de la requête pour référence:
#get all users in meetings with Frank, (frank.id == 1)
um = aliased(UserMeeting)
frank = User.query.get(1)
q = session.query(User).join(User.attendingMeetings).\
filter(UserMeeting.meeting_id == um.meeting_id).\
filter(UserMeeting.user_id != frank.id, um.user_id == frank.id)
users_meeting_with_frank = q.all()