获取在24小时内回复了对话的第一条消息的用户

时间:2017-03-31 16:53:55

标签: mysql sql

我需要找到在 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小时内回复。

4 个答案:

答案 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;