SQL:如何将两列作为无序对进行GROUP BY?

时间:2015-06-06 11:46:19

标签: python mysql sql sqlalchemy

我正在使用SQLAlchemy作为我的ORM实现与MySQL的聊天系统 我的表格包含以下列:id, from_user_id, to_user_id, message, time_sent.

我正在尝试创建一个查询,在其中我选择包含每个会话发送的最新消息的记录。这就像人们在Facebook上看到的对话列表一样。
关于如何做到这一点的任何想法?
以下是我到目前为止的情况:

latest_msg_sq = (DBSession.query(func.max(Message.id).label("max_id"))
.group_by(Message.from_user)).subquery()    
matching_conv = DBSession.query(Message)
.join(latest_msg_sq, and_(Message.id ==  
latest_msg_sq.c.max_id)).order_by(Message.time_sent.desc()) 

不幸的是,它不能很好地工作,因为它只获取from_user_id的最新消息。我需要它来考虑来自to_user_id的消息,而group_by似乎不是最好的方法。在我看来,我认为我需要将记录from_user_id和to_user_id视为无序对,然后在这些对上使用group_by。但是,我不知道该怎么做。

3 个答案:

答案 0 :(得分:1)

在MySQL中,您可以使用least()greatest()。要获得最近的时间:

select least(from_user_id, to_user_id) as u1, greatest(from_user_id, to_user_id) as u2,
       max(time_sent) as maxts
from messages
group by least(from_user_id, to_user_id), greatest(from_user_id, to_user_id)

要获取完整的消息,您可以将其加入:

select m.*
from (select least(from_user_id, to_user_id) as u1, greatest(from_user_id, to_user_id) as u2,
             max(time_sent) as maxts
      from messages
      group by least(from_user_id, to_user_id), greatest(from_user_id, to_user_id)
     ) m2 join
     messages m
     on least(m2.from_user_id, m2.to_user_id) = least(m.from_user_id, m.to_user_id) and
        greatest(m2.from_user_id, m2.to_user_id) = greatest(m.from_user_id, m.to_user_id)

我不确定你会如何在SQLalchemy中表达这一点。

答案 1 :(得分:1)

试试这个:

select msg1.* from message msg1
left outer join message msg2 on 
(msg1.from_user_id = msg2.from_user_id 
and msg1.to_user_id = msg2.to_user_id and msg2.time_sent > msg1.time_sent)
left outer join message msg3 on 
msg1.to_user_id = msg3.from_user_id 
and msg1.from_user_id= msg3.to_user_id and msg3.time_sent > msg1.time_sent
where msg2.id is null and msg3.id is null

答案 2 :(得分:1)

Mohnsen Heydari的SQLAlchemy版本为所有需要它的人提供了答案:

msg1 = aliased(Message)
msg2 = aliased(Message)
msg3 = aliased(Message)
matching_conv = DBSession.query(msg1)
matching_conv = matching_conv.outerjoin(msg2, and_(msg1.from_user==msg2.from_user, msg1.to_user==msg2.to_user, msg2.id > msg1.id))
matching_conv = matching_conv.outerjoin(msg3, and_(msg1.to_user==msg3.from_user, msg1.from_user==msg3.to_user, msg3.id > msg1.id))
matching_conv = matching_conv.filter(and_(msg2.id == None, msg3.id == None)).order_by(msg1.time_sent.desc())