我正在2个用户之间建立聊天系统。 我有一个看起来像这样的聊天表:(这是架构:SQL Fiddle)
--------------------------------------------------------------------------------
| message_id | sender_id | receiver_id | message_text | date |
--------------------------------------------------------------------------------
| 1 | 20 | 100 | Hello mate | 2018-04-29 12:15:33 |
--------------------------------------------------------------------------------
| 2 | 100 | 20 | Hi there | 2018-04-29 13:20:05 |
--------------------------------------------------------------------------------
| 3 | 13 | 44 | Alright | 2018-04-29 14:35:15 |
--------------------------------------------------------------------------------
| 4 | 20 | 57 | Hi user 57 | 2018-04-29 16:44:34 |
--------------------------------------------------------------------------------
我想从用户参与的每个聊天中获取最后消息的行,因此在上面的示例中,用户20应该获得2行:message_id 2行(因为他正在与用户100进行聊天) ,虽然他没有发送最后一条消息),并且有一行message_id 4(因为他向用户57发送了消息) 它基本上就像WhatsApp,你总是在顶部有任何聊天的第一条消息。
问题是,如果用户是SENDER,我只能收到最后一条消息而不是他是接收者:
SELECT * FROM chat
WHERE message_id IN
(SELECT MAX(message_id) FROM chat WHERE sender_id=:sender_id
GROUP BY receiver_id) ORDER BY date DESC
我想我应该添加另一栏" chat_id"对于同一个聊天中的每2个用户来说,这是一个相同的数字(因此,无论用户100和20是发送者还是接收者,用户100和20将具有相同的chat_id,并且用户13和44在此示例中将具有不同),
或者,有更好的选择吗?
答案 0 :(得分:0)
你可以使用发送者和接收者之间的联合来获得两者的结果
You could use
select *
from chat
inner join (
select max(message_id) max_id, user from (
select message_id, sender_id as user
from chat
union
select message_id, receiver_id
from chat) t
) t1 on t1.max_id = chat.message_id
and chat.sender_id=:sender_id
答案 1 :(得分:0)
要有效地处理这个问题,请从这两个查询开始:
select message_id, sender_id as other_id
from messages
where receiver_id = :user
order by message_id desc;
select message_id, receiver_id as other_id
from messages
where sender_id = :user
order by message_id desc;
这些可以使用两个索引进行优化:messages(receiver_id, sender_id, message_id)
和messages(sender_id, receiver_id, message_id)
。
您可以union all
将它们放在一起并进行排序或聚合以获得最大值:
select m.*
from messages m
where m.message_id in (select max(message_id)
from ((select message_id, sender_id as other_id
from messages
where receiver_id = :user
order by message_id desc
limit 1
) union all
(select message_id, receiver_id as other_id
from messages
where sender_id = :user
order by message_id desc
limit 1
)
) mm
);
子查询应该能够使用索引(实际上,"其他id"不需要)。然后,max()
分为两行,in
应该能够利用(message_id)
上的索引。
编辑:
对于修订后的问题,我无法想出一个真正有效的方法。这是一种方法:
select m.*
from messages m
where m.message_id in (select max(m2.message_id)
from messages m2
where :user in (sender_id, receiver_id)
group by (case when sender_id = :user then receiver_id else sender_id end)
);