【问题标题】:Querying multiple joined inherited tables filtered by a many-to-many relationship查询由多对多关系过滤的多个连接继承表
【发布时间】:2012-11-18 13:29:34
【问题描述】:

我有一个大致如下所示的 SQLAlchemy 方案:

participation = db.Table('participation',
        db.Column('artist_id', db.Integer, db.ForeignKey('artist.id'),
                  primary_key=True),
        db.Column('song_id', db.Integer, db.ForeignKey('song.id'),
                  primary_key=True),
)

class Streamable(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    kind = db.Column(db.String(10), nullable=False)
    score = db.Column(db.Integer, nullable=False)
    __mapper_args__ = {'polymorphic_on': kind}

class Artist(Streamable):
    id = db.Column(db.Integer, db.ForeignKey('streamable.id'), primary_key=True)
    name = db.Column(db.Unicode(128), nullable=False)
    __mapper_args__ = {'polymorphic_identity': 'artist'}

class Song(Streamable):
    id = db.Column(db.Integer, db.ForeignKey('streamable.id'), primary_key=True)
    name = db.Column(db.Unicode(128), nullable=False)
    artists = db.relationship("Artist", secondary=participation,
                              backref=db.backref('songs'))
    __mapper_args__ = {'polymorphic_identity': 'song'}

class Video(Streamable):
    id = db.Column(db.Integer, db.ForeignKey('streamable.id'), primary_key=True)
    song_id = db.Column(db.Integer, db.ForeignKey('song.id'), nullable=False)
    song = db.relationship('Song', backref=db.backref('videos', lazy='dynamic'),
                           primaryjoin="Song.id==Video.song_id")
    __mapper_args__ = {'polymorphic_identity': 'video'}

我想对具有特定艺术家的歌曲或视频进行一次查询;即,这两个查询在一个查询中(所有查询都应该是.order_by(Streamable.score)):

q1=Streamable.query.with_polymorphic(Video)
q1.join(Video.song, participation, Artist).filter(Artist.id==1)
q2=Streamable.query.with_polymorphic(Song)
q2.join(participation, Artist).filter(Artist.id==1)

这是我达到的最好的;它发出可怕的 SQL 并且总是产生空结果(不知道为什么):

p1=db.aliased(participation)
p2=db.aliased(participation)
a1=db.aliased(Artist)
a2=db.aliased(Artist)
q=Streamable.query.with_polymorphic((Video, Song))
q=q.join(p1, a1).join(Video.song, p2, a2)
q.filter(db.or_((a1.id==1), (a2.id==1))).order_by('score')

如果有的话,执行此查询的正确方法是什么(也许关系数据存储不适合我的工作...)?

【问题讨论】:

    标签: sqlalchemy flask-sqlalchemy


    【解决方案1】:

    您的查询基本上是正确的。我认为从join 更改为outerjoin 应该可以解决问题:

    q=q.outerjoin(p1, a1).outerjoin(Video.song, p2, a2)
    

    我还将order_by 替换为:

    q = q.order_by(Streamable.score)
    

    【讨论】:

    • 切换到外连接使查询返回歌曲,但没有视频。仅查询 id==1 的艺术家的视频确实有效。
    • 奇怪,我的示例代码两者都找到了...可能是因为您的示例代码有a2.id==2而不是a2.id==1
    • 那个错字确实很尴尬,但事实并非如此。即使我修复了它,我仍然只能得到歌曲。我再次验证了我的单独查询(我原始问题中的中间代码块)实际上确实返回了艺术家 1 的视频和艺术家 1 的歌曲。此外,我编辑了原始问题以删除错字(a2.id==1),以免迷惑人们。如果有帮助的话,我愿意从pg_dump 分享我的计划……还有其他想法吗?
    • 好的。检查代码snipt.org/waaab1。如果您运行脚本,它会返回一个视频和一首歌曲...
    • 你说的太全面了,非常感谢!我仍然不确定为什么,但是当我在玩答案并试图理解出了什么问题时,我重新创建了我的数据库方案并从我拥有的示例数据中重新创建了数据,问题就消失了。我想我的计划或数据有问题,但outerjoins 肯定是造成重要差异的原因。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2021-12-10
    • 2016-03-08
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    相关资源
    最近更新 更多