3

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

我的桌子:

+--------------+         +---------------------+
|   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')。

4

5 回答 5

5

您正在寻找groupwise maximum,可以通过首先对users_messages表格进行分组thread_id并选择来找到它MAX(sent_at),然后将结果连接回users_messages表格以查找该最大记录的其他字段。

我发现这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
于 2012-09-02T15:48:10.677 回答
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
于 2012-08-31T13:25:39.107 回答
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>启动或参与的每个线程中的最新消息。

最新消息基于id每个 thread_id 的最大值。

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

  • idinusers_messages是每个新行的唯一自动递增 int 。
  • 每个线程包含不超过两个用户之间的对应关系。

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

于 2012-09-03T02:02:17.317 回答
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;`
于 2012-08-31T13:18:02.533 回答
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 函数。
于 2012-09-05T13:43:28.203 回答