我需要找到在 24小时内回复了对话的第一条消息(一对一对话)的用户。我有一个消息表,其中存储了所有数据。
表:消息
id | sender_id | recipient_id | content | Created_at
1 | 1001 | 256 | Hi | 2017-03-20 22:37:30
2 | 256 | 1001 | Hello | 2017-03-21 20:29:10
3 | 1001 | 256 | XYZ | 2017-03-21 22:02:00
4 | 256 | 1001 | ??? | 2017-03-21 23:01:01
5 | 1002 | 500 | Hi there | 2017-03-22 10:10:10
6 | 1002 | 500 | Can you meet?| 2017-03-22 10:15:32
7 | 500 | 1002 | Yes | 2017-03-22 10:20:30
8 | 1003 | 600 | Hello world | 2017-03-23 01:00:00
9 | 1004 | 700 | Hi | 2017-03-23 08:10:10
10 | 700 | 1004 | hello | 2017-03-26 22:00:00
预期结果:
users
256
500
示例:用户1001和256之间的对话。
id | sender_id | recipient_id | content | Created_at
1 | 1001 | 256 | Hi | 2017-03-20 22:37:30
2 | 256 | 1001 | Hello | 2017-03-21 20:29:10
3 | 1001 | 256 | XYZ | 2017-03-21 22:02:00
4 | 256 | 1001 | ??? | 2017-03-21 23:01:01
此处2 | 256 | 1001 | Hello | 2017-03-21 20:29:10
是对话的第一条回复消息,并在24小时内回复。
答案 0 :(得分:2)
我已经对此进行了测试,但它确实有效。它与其他答案大致相同。
select messages.sender_id as users from (
select t.id1, t.id2, t.start, messages.sender_id as initiator,
messages.recipient_id as replier from (
select greatest(sender_id, recipient_id) as id1,
least(sender_id, recipient_id) as id2, min(Created_at) as start
from messages group by id1, id2
) as t left join messages on messages.Created_at = t.start
and ((messages.sender_id = t.id1 and messages.receiver_id = t.id2)
or (messages.sender_id = t.id2 and messages.receiver_id = t.id1))
) as t inner join messages on messages.sender_id = t.replier
and messages.recipient_id = t.initiator
and messages.Created_at < date_add(t.start, interval 1 day)
group by users;
最里面的查询通过对所涉及的两个用户对邮件进行分组来查找对话,并通过采用最小Created_at
来查找该对话的开始。
中间查询通过查找对话中的第一条消息来查找发起者和回复者。
外部查询在启动后的一天内查找从回复者到发起者的消息(因此在该对话中),并按用户分组,以便它们每次只出现一次(即使涉及多个对话)
答案 1 :(得分:1)
好的。
首先,我们需要定义对话的内容:一对(sender_id,recipient_id)交换消息。确定对话中的第一条消息有点棘手。我们可以这样做:
SELECT sender_id, recipient_id, min(created_at) FROM messages
GROUP BY sender_id, recipient_id
但是,这将为我们提供每个会话的前两条消息。我们仍然不知道是谁开始的,谁回答的却没有看日期,但我们得到的数据就是我们需要回答的问题。它可能很快,因为我将假设一个索引(sender_id,recipient_id,created_at)。
现在,我看到两种解决方法。第一个:
SELECT least(sender_id,recipient_id),
greatest(sender_id,recipient_id),
max(created_at) <= DATE_ADD( min(created_at), INTERVAL 1 DAY )
FROM (
SELECT sender_id, recipient_id, min(created_at) FROM messages
GROUP BY sender_id, recipient_id
) foo
GROUP BY least(sender_id,recipient_id),
greatest(sender_id,recipient_id)
HAVING count(*)=2;
least()和great()允许为发送方和接收方ID的每个会话创建一个id。 max()和min()将返回第一条消息及其回复,因为每个对话只有2行。并且必须删除邮件而不回复。
我们也可以使用临时表:
CREATE TEMPORARY TABLE foo (
sender_id INT NOT NULL,
recipient_id INT NOT NULL,
createdèat DATETIME NOT NULL
);
INSERT INTO foo
SELECT sender_id, recipient_id, min(created_at) FROM messages
GROUP BY sender_id, recipient_id
ALTER TABLE foo ADD PRIMARY KEY (sender_id,recipient_id);
SELECT ... substract a.created_at and b.created_at to get your 24h limit
FROM foo a
JOIN foo b ON ( a.sender_id=b.recipient_id
AND a.recipient_id=b.sender_id
AND a.created_at < b.created_at)
通过将临时表连接到自身,我们将第一条消息及其回复放在一个查询中,我们可以比较它们的日期。
答案 2 :(得分:0)
在未经测试的情况下进行挥杆,因为我认为理想的结果仍不清楚。
首先,找到对话的“第一条消息”:
select m1.id
,m.sender_id
,m.recipient_id
,m.Created_at
from messages m1
inner join (
select m.sender_id
,m.recipient_id
,Min(m.Created_at) as first_message
from messages m
group by m.sender_id
,m.recipient_id
) m2
on m1.sender_id = m2.sender_id
and m1.m.recipient_id = m2m.recipient_id
and m1.Created_at = m2.first_message
如果这些是正确的“第一条消息”,那么请在24小时内找到任何回复
select distinct m3.sender_id
from messages m3
inner join (
<the above first message select statement>
) fm
on m3.sender_id = fm.recipient_id
and m3.recipient_id = fm.sender_id
and m3.Created_at < DATEADD (HH , 24 , fm.Created_at)
where m3.Created_at > fm.Created_at
答案 3 :(得分:0)
这将在24小时内向用户返回最后一条消息
select
cnv.id ,
cnv.sender_id,
cnv.recipient_id,
cnv.content,
cnv.Created_at
from
(
-- first create a table with costum id of conversaton
select
-- ex: 1001-256
concat(greatest(sender_id, recipient_id),'-',least(sender_id, recipient_id) ) as 'cnv_id', -- costum column for joining
id ,
sender_id,
recipient_id,
content,
Created_at
from message
) cnv
INNER JOIN
(
-- second extract the last date of every one to one coversation conversation
-- result ex : 1001-256 | 2017-03-21 23:01:01
SELECT
concat(greatest(sender_id, recipient_id),'-',least(sender_id, recipient_id) ) as 'cnv_id', -- costum column for joining
max(Created_at) 'max_date'
group by cnv_id
) max_cnv ON cnv.cnv_id = max_cnv.cnv_id -- join the two result by the custom cnv_id
WHERE
-- here we extract only the record that there Created_at is > 24 hours from the max date
-- you can make this condition as you want but i think this will work
(max_cnv.max_date - cnv.Created_at)/1000/60 >= 24;