从每个对话中获取最后一条消息

Posted

技术标签:

【中文标题】从每个对话中获取最后一条消息【英文标题】:Get last message from each conversation 【发布时间】:2016-03-24 09:47:46 【问题描述】:

我知道以前有人问过类似的问题,但他们都没有同样的条件,他们的答案不适用于这种情况。

包含消息的表格如下所示:

id | owner_id | recipient_id | content      | created
 1 |        1 |            2 | Hello        | 2015-12-08 20:00
 2 |        2 |            1 | Hey          | 2015-12-08 20:10
 3 |        3 |            1 | You there?   | 2015-12-08 21:00
 4 |        1 |            3 | Yes          | 2015-12-08 21:15
 5 |        4 |            1 | Hey buddy    | 2015-12-08 22:00

假设我从用户 ID 1 的每个对话中查询最后一条消息,预期结果是:

id | owner_id | recipient_id | content      | created
 5 |        4 |            1 | Hey buddy    | 2015-12-08 22:00
 4 |        1 |            3 | Yes          | 2015-12-08 21:15
 2 |        2 |            1 | Hey          | 2015-12-08 20:10

我尝试了很多组合,使用了 JOIN 和子查询,但没有一个给出预期的结果。

这是我尝试过的查询之一,但它不起作用。我相信它甚至不接近我需要的东西。

SELECT
    IF ( owner_id = 1, recipient_id, owner_id ) AS Recipient,

    (
        SELECT
            content
        FROM
            messages

        WHERE
            ( owner_id = 1 AND recipient_id = Recipient  )
        OR
            ( owner_id = Recipient AND recipient_id = 1 )

        ORDER BY
            created DESC

        LIMIT 1
    )
FROM
    messages

WHERE
    owner_id = 1
OR
    recipient_id = 1

GROUP BY
    Recipient;

【问题讨论】:

你的表中是否有唯一键? 是的,我更新了问题(拼错了几个 ID)。 能否请您在问题中包含您尝试过的 SQL 查询? 对不起,太累了,无法给出正确的答案,但您基本上必须按对话的“其他用户”分组,这可以通过caseif 中的GROUP_BY 语句来实现。在该组中选择 max(id) by,然后选择 where id in (group by query)。 那里,添加了我尝试过的查询之一@summea 【参考方案1】:
select t.* 
    from 
        t 
      join 
        (select user, max(created) m  
            from 
               (
                 (select id, recipient_id user, created 
                   from t 
                   where owner_id=1 ) 
               union 
                 (select id, owner_id user, created
                   from t 
                   where recipient_id=1)
                ) t1
           group by user) t2
     on ((owner_id=1 and recipient_id=user) or 
         (owner_id=user and recipient_id=1)) and 
         (created = m)
   order by created desc

example on sqlfiddle

【讨论】:

此查询返回预期结果,非常感谢!虽然我仍在试图弄清楚它是如何工作的。 不客气!如果你愿意,我可以写一些解释 那太好了@splash58【参考方案2】:

这应该可以解决问题:

$joins = array(
    array('table' => 'conversations',
        'alias' => 'Conversation2',
        'type' => 'LEFT',
        'conditions' => array(
            'Conversation.id < Conversation2.id',
            'Conversation.owner_id = Conversation2.owner_id',
        )
    ),
    array('table' => 'conversations',
        'alias' => 'Conversation3',
        'type' => 'LEFT',
        'conditions' => array(
            'Conversation.id < Conversation3.id',
            'Conversation.recepient_id = Conversation3.recepient_id',
        )
    )

);

$conditions = array(
    'OR' => array(
        array(
            'Conversation2.id'=>null,
            'Conversation.owner_id' => $ownerId
        ),
        array(
            'Conversation3.id'=>null,
            'Conversation.recipient_id' => $ownerId
        ),
     )
);

$order = array('Conversation.created'=>'DESC');

$lastConversations=$this->Conversation->find('all',compact('conditions','joins','order'));

假设表的名称是conversations,而您的模型名称是Conversation。它基于Retrieving the last record in each group 的公认答案中描述的技术。

【讨论】:

这个好像很接近。到目前为止唯一的问题是结果没有按最新排序。尝试添加“order”参数,但没有解决问题。 @Camilo 我添加了 ORDER BY 子句。 谢谢。我试过了,问题仍然存在。还注意到分组没有按预期工作。我会坚持使用 SQL 的答案,无论如何,谢谢!【参考方案3】:

这个解决方案最适合我。

    SELECT t1.*
    FROM chats AS t1
    INNER JOIN
    (
        SELECT
            LEAST(sender_id, receiver_id) AS sender_id,
            GREATEST(sender_id, receiver_id) AS receiver_id,
            MAX(id) AS max_id
        FROM chats
        GROUP BY
            LEAST(sender_id, receiver_id),
            GREATEST(sender_id, receiver_id)
    ) AS t2
        ON LEAST(t1.sender_id, t1.receiver_id) = t2.sender_id AND
           GREATEST(t1.sender_id, t1.receiver_id) = t2.receiver_id AND
           t1.id = t2.max_id
        WHERE t1.sender_id = ? OR t1.receiver_id = ?

Source

【讨论】:

所选答案有什么问题?为什么这对您更有效? 嗯,好问题,据我所知,它并没有按我的意愿检索消息。就像不在订单中或所有我想要的一样

以上是关于从每个对话中获取最后一条消息的主要内容,如果未能解决你的问题,请参考以下文章

如何将每个用户的最后一条消息显示给用户对话以保留聊天记录?

获取每组的最后一行

Laravel 按最后一条消息对对话进行排序

解析 JSON Facebook 对话 XCODE

返回子查询中的最后一条记录 - MySQL

如何获取每个用户的对话并包含消息?