通过会话线程中的最新响应对消息进行分组

时间:2012-08-31 12:36:15

标签: mysql

我需要在用户之间建立一个简单的内部消息传递系统。

我的桌子:

+--------------+         +---------------------+
|   messages   |         |        users        |
+----+---------+         +---------------------+
| id | message |         | id | username | ... 
+----+---------+         +---------------------+

+------------------------------------------------------------------------------+
|                                 users_messages                               |
+------------------------------------------------------------------------------+
| id | from_usr_id | to_usr_id | msg_id | thread_id | read | sent_at | read_at |
+------------------------------------------------------------------------------+

INT 'thread_id'表示会话线程,用于对邮件进行分组。

BOOLEAN 'read'表示用户是否打开/查看了该消息。

我希望按'thread_id'对邮件进行分组,按'sent_at'排序,以便我可以按线程向用户显示他的最新消息。我还要计算每个帖子中的消息。

我想为特定用户ID获取类似内容:

+----------------------------------------------------------------------------
| last_messages_by_conversation
+----------------------------------------------------------------------------
| message | from_username | sent_at | count_thread_msgs | count_unread_msg |
+----------------------------------------------------------------------------

TEXT 'message'是特定'thread_id'

中的最新消息

VARCHAR 'from_username'DATETIME 'sent_at'与最新消息相关。

INT 'count_thread_msgs'INT 'count_unread_msg'与线程相关,表示线程中的消息总数和未读消息数。

每一行代表一个线程/对话(按'thread_id'分组),显示该特定线程的最后一条消息(按'sent_at'排序)。

5 个答案:

答案 0 :(得分:5)

您正在寻找groupwise maximum,首先可以通过users_messagesthread_id表进行分组并选择MAX(sent_at),然后将结果重新加入users_messages来找到{{3}}。 {1}}表来查找该最大记录的其他字段。

我发现NATURAL JOIN是一个非常方便的捷径:

SELECT   messages.message,
         users.username AS from_username,
         t.sent_at,
         t.count_thread_msgs,
         t.count_unread_msg
FROM     users_messages NATURAL JOIN (
  SELECT   thread_id,
           to_usr_id,
           MAX(sent_at)  AS sent_at,
           COUNT(*)      AS count_thread_msgs,
           SUM(NOT read) AS count_unread_msg
  FROM     users_messages
  WHERE    to_usr_id = ?
  GROUP BY thread_id
) t JOIN messages ON messages.id = users_messages.msg_id
    JOIN users    ON users.id    = users_messages.from_usr_id

答案 1 :(得分:2)

SELECT 
      users.id,
      users.username,
      user_messages.thread_id,
      user_messages.unread ,
      messages.message 
FROM users
LEFT JOIN (SELECT 
                 from_usr_id , 
                 msg_id,
                 count(thread_id)) as thread_id,
                 count(read_at) as  unread  
          FROM user_messages)as user_messages on user_messages.from_usr_id = users.id
LEFT JOIN messages on messages.id = user_messages.msg_id

答案 2 :(得分:2)

您可以尝试此解决方案:

SELECT   c.message,
         d.username AS from_username,
         b.sent_at,
         a.count_thread_msgs,
         a.count_unread_msg
FROM     (
         SELECT   MAX(id)  AS maxid,
                  COUNT(*) AS count_thread_msgs,
                  COUNT(CASE WHEN `read` = 0 AND <uid> = to_usr_id THEN 1 END) AS count_unread_msg
         FROM     users_messages
         WHERE    <uid> IN (from_usr_id, to_usr_id)
         GROUP BY thread_id
         ) a
JOIN     users_messages b ON a.maxid       = b.id
JOIN     messages c       ON b.msg_id      = c.id
JOIN     users d          ON b.from_usr_id = d.id
ORDER BY b.sent_at DESC

这会在用户<uid>启动或参与的每个线程中获取最新消息。

最新消息基于每个thread_id的最高id

此解决方案做出以下假设:

  • id中的users_messages是每个新行的唯一自动递增int。
  • 每个主题包含至少两个用户之间的对应关系。

如果线程可以包含两个以上的用户,则需要稍微调整查询,以便获得准确的计数聚合。

答案 3 :(得分:1)

试试这个并告诉我们,为您的$$改变user ID ..

select u.username,msg.message,m.sent_at,

(select count(*) from user_message where read=0 and to_usr_id=$$) as count_thread_msgs,

(select count(*) from user_message where to_usr_id= $$) as count_unread_msg

from users as u join user_messages as m

on u.id=m.id where u.id=$$ 

join messages as msg on msg.id=m.id

group by u.id;`

答案 4 :(得分:0)

尝试此查询 -

SELECT
  m.message,
  u.username from_username,
  um1.sent_at,
  um2.count_thread_msgs,
  um2.count_unread_msg
FROM users_messages um1
  JOIN (
       SELECT
         thread_id,
          MAX(sent_at) sent_at,
          COUNT(*) count_thread_msgs,
          COUNT(IF(`read` = 1, `read`, NULL)) count_unread_msg
        FROM users_messages GROUP BY thread_id) um2
    ON um1.thread_id = um2.thread_id AND um1.sent_at = um2.sent_at
JOIN messages m
  ON m.id = um1.msg_id
JOIN users u
  ON u.id = um1.from_usr_id
-- WHERE u.id = 100 -- specify user id here

您的问题的答案:

  1. 关于上次日期时间:我稍微更改了一下查询,只需尝试新的查询。
  2. 关于特定用户:添加WHERE条件以过滤用户 - ...WHERE u.id = 100
  3. 关于许多记录:因为您加入了另一个表(messagesusers),并且可能有多条记录具有相同的thread_id。为避免这种情况,您应该按thread_id字段对结果集进行分组,并使用聚合函数来获得单个结果,例如使用GROUP_CONCAT函数。