试着写一个查询来选择由我,我的朋友或朋友喜欢的帖子写的帖子

时间:2012-05-14 21:13:10

标签: mysql sql sqlalchemy

我有3个表 - 帖子,友情和喜欢 - 下面描述的重要字段。

帖子:id, user_id, title

友谊:requester_id, accepter_id, is_confirmed

喜欢:post_id, user_id

我有一个名为get_relevant_posts()的方法,它应该返回我写过的帖子,我确认的朋友已经写过的帖子,或者我确认的朋友喜欢的帖子。我已经在SQLAlchemy中实现了这个,但是我的查询中存在一个错误,因为只有在友谊表不为空时它才有效(无关紧要是什么,只是不能为空)。如果它是空的,则不会返回任何内容(不正确的连接?)。

这不是一个大问题,因为友谊表在99.99%的时间里会有一些东西。但我仍然想退一步用纯SQL编写这个 - 我似乎无法绕过它。

SQLALCHEMY CODE

Friendship1 = aliased(Friendship)
Friendship2 = aliased(Friendship)
Friendship3 = aliased(Friendship)
Friendship4 = aliased(Friendship)
return (DBSession.query(Post)
        .outerjoin(Friendship1, Post.user_id==Friendship1.accepter_id)
        .outerjoin(Friendship2, Post.user_id==Friendship2.requester_id)
        .outerjoin(Like, Post.id==Like.post_id)
        .filter(or_(
            # My post
            self.id==Post.user_id,
            # My friends post, where I'm the requester of the friendship
            and_(self.id==Friendship1.requester_id,
                 Friendship1.is_confirmed==True),
            # My friends post, where I'm the accepter of the friendship
            and_(self.id==Friendship2.accepter_id,
                 Friendship2.is_confirmed==True),
            # Somebodies post, which my friends found interesting
            and_(self.id==Friendship3.requester_id,
                 Friendship3.is_confirmed==True,
                 Like.user_id==Friendship3.accepter_id),
            and_(self.id==Friendship4.accepter_id,
                 Friendship4.is_confirmed==True,
                 Like.user_id==Friendship4.requester_id)))
        .order_by(Post.created_at.desc())
        .limit(limit)
        .offset(offset)
        .all())

生产此

SELECT posts.title AS posts_title
FROM friendships AS friendships_1, friendships AS friendships_2, posts LEFT OUTER JOIN friendships AS friendships_3 ON posts.user_id = friendships_3.accepter_id LEFT OUTER JOIN friendships AS friendships_4 ON posts.user_id = friendships_4.requester_id LEFT OUTER JOIN likes ON posts.id = likes.post_id LEFT OUTER JOIN users AS users_1 ON users_1.id = posts.user_id 
WHERE (posts.user_id = %s OR friendships_3.requester_id = %s AND friendships_3.is_confirmed = %s OR friendships_4.accepter_id = %s AND friendships_4.is_confirmed = %s OR friendships_1.requester_id = %s AND friendships_1.is_confirmed = %s AND likes.user_id = friendships_1.accepter_id OR friendships_2.accepter_id = %s AND friendships_2.is_confirmed = %s AND likes.user_id = friendships_2.requester_id) ORDER BY posts.created_at DESC 
LIMIT %s

2 个答案:

答案 0 :(得分:0)

假设我们有MS SQL 2005

With rels
(
   Select f.requesterId as target_id
   From friendships f 
   Where is_confirmed = 1 and f.accepter_id='Your Id'
   Union 
   Select 'Your id'
)
Select p.*
From posts p 
  left join rel r on r.target_id = p.user_id  -- this will be null on for non-target users
  left join likes l on p.post_id=l.post_id -- here we will pick likes
  left join rel r1 on r1.target_id=l.user_id
where coalesce(r1.target_id, r2.target_id) is not null -- telling sql to pick posts we are interested in

或用子查询替换CT​​E rel。

答案 1 :(得分:0)

以不同的方式解决它。使用IN子句执行子查询以检查是否有任何喜欢该帖子的用户是我确认的朋友列表的一部分。其他部分非常直观(检查我是写它还是朋友写的)。