在MySQL(消息系统)中返回多个收件人名称

时间:2011-04-12 19:27:05

标签: php mysql database

我正在创建一个类似于iPhone SMS系统的多收件人线程邮件系统(收件箱和发件箱都合并为一个显示器,两个用户之间只能存在一个线程)。

使用senderid列(例如“11”)和接收者列(例如“,13,10,15,20”)存储消息。为了存储多个收件人,我用逗号分隔它们并用“%”+“,$ userid”和“#”调用查询字段。这样做的问题在于它弄乱了LEFT JOIN,它将recipientsid连接到users表(具有用户名)。

这是我当前的查询:

$sql = 
  "SELECT DISTINCT CASE 
   WHEN $userid != senderid THEN senderid ELSE recipients END someid,   
   CASE WHEN 13 != senderid THEN senders.username ELSE receivers.username END somename,
   messages.body, 
   messages.time 
   FROM messages 
   LEFT JOIN users AS senders ON messages.senderid = senders.id
   LEFT JOIN users AS receivers ON messages.recipients = receivers.id
   WHERE messages.recipients = '#' + ',$userid,' + '#'
   OR messages.senderid = $userid
   ORDER BY messages.time";

以下是我想要做的事情:

  • 如果收件人中只有一个收件人ID(内容看起来像“,id”),则删除id周围的逗号以查找sendername(LEFT JOIN users AS receiver ON messages.recipients(WITHOUT COMMAS) )= receivers.id。

  • 如果收件人中有多个收件人ID(内容类似于“,id,id2,id3”等),则以某种方式提取与ID对应的所有名称并将结果存储为类似于以下内容:sendername =“Name1,Name2,Name3”;。

任何人都知道如何处理这个问题?一个子查询可能吗?我非常感谢你的帮助。

1 个答案:

答案 0 :(得分:1)

第一。而不是:

WHERE messages.recipients = '#' + ',$userid,' + '#'

你可以删除开头和结尾的逗号并使用:

WHERE FIND_IN_SET($userid, messages.recipients) > 0

所以你也可以为LEFT JOIN设置这个条件:

LEFT JOIN users AS receivers
  ON FIND_IN_SET(receivers.id, messages.recipients) > 0

然后按消息分组,并使用GROUP_CONCAT()连接名称。

这样的事情:

  SELECT senders.name AS senderName
       , messages.body
       , messages.time 
       , GROUP_CONCAT( receivers.name
                       ORDER BY receivers.id
                       SEPARATOR ','
                     )
         AS receiversNames
  FROM messages 
    LEFT JOIN users AS senders
      ON messages.senderid = senders.id
    LEFT JOIN users AS receivers
      ON FIND_IN_SET(receivers.id, messages.recipients) > 0
  GROUP BY messages.id
  ORDER BY messages.time

将为您提供所有发件人姓名和收件人姓名连接的邮件。

我猜每封邮件都有1个(或零)发件人。如果没有,并且某些消息包含多个发件人,那么您可能需要编辑GROUP BY

警告:当表格中有很多行时,此类查询可能会很慢(甚至非常慢)。 messages.recipients上无法使用索引,从而减慢了查询速度。因此,您现在最好考虑使用MessageRecipient中间表规范化您的结构。