3

次のテーブル定義があります。

subscriptions = db.Table("subscriptions",
    db.Column("subscriber_id", db.Integer, db.ForeignKey("users.id"),
        primary_key=True),
    db.Column("subscribee_id", db.Integer, db.ForeignKey("users.id"), 
        primary_key=True),
)


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)

    subscribes = db.relationship('User', secondary=subscriptions,
        backref=db.backref('subscribed'),
        primaryjoin="User.id==subscriptions.c.subscriber_id",
        secondaryjoin="User.id==subscriptions.c.subscribee_id",
    )

特定のユーザーを購読しているが、そのユーザーが購読していないすべてのユーザーを選択するクエリを作成する必要があります。私はすでに Python でこれを行うことができます (おそらく、私の説明よりも正確に私が望むものをより明確に示しているでしょう):

filter(lambda u: u not in self.subscribes, self.subscribed)
# OR: set(self.subscribed) - set(self.subscribes)

しかし、SQL 側で行うと速くなりませんか?

4

3 に答える 3

3

これが SQL で行われた場合、クエリは次のようになると思います。

SELECT
    u.id
FROM
    subscriptions sub  JOIN
    users u ON u.id = sub.subscriber_id LEFT JOIN
    subscriptions unsub
        ON unsub.subscribee_id = sub.subscriber_id
        AND unsub.subscriber_id= sub.subscribee_id 
WHERE
    sub.subscribee_id = :user_id
    AND unsub.subscribee_id IS NULL
于 2012-08-08T20:02:57.227 に答える
2

SQLALchemy のソリューションは次のとおりです (Michael Fredrickson によるソリューションの翻訳にすぎません)。

User1 = aliased(User)
sub = aliased(subscriptions)
unsub = aliased(subscriptions)


qry = db.session.query(User1).select_from(sub).\
    join(User1, User1.id==sub.c.subscriber_id).\
    filter(sub.c.subscribee_id==self.id).\
    outerjoin(unsub,
        and_(unsub.c.subscribee_id==sub.c.subscriber_id,
             unsub.c.subscriber_id==sub.c.subscribee_id)).\
    filter(unsub.c.subscribee_id==None).\
    order_by(User1.name.desc())
于 2012-08-08T22:14:21.330 に答える
0

データベースがOracleの場合、最後のコメントのマイナス記号と同じように、セットで機能する「MINUS」キーワードを使用できます。以下は、「UNION」クエリと同様に構造化された単一のステートメントです。

SELECT subscriber_id FROM subscriptions WHERE subscribee_id = :myuid
MINUS
SELECT subscribee_id FROM subscriptions WHERE subscriber_id = :myuid

または、「MINUS」が使用できない場合は、「NOT IN」を使用できます。

SELECT subscriber_id
FROM subscriptions
WHERE subscribee_id = :myuid
  AND subscriber_id NOT IN
        (SELECT subscribee_id FROM subscriptions WHERE subscriber_id = :myuid)
于 2012-08-08T20:20:16.640 に答える