【问题标题】:Returning multiple recipients names in MySQL (messaging system)在 MySQL(消息系统)中返回多个收件人姓名
【发布时间】:2011-04-12 19:27:04
【问题描述】:

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

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

这是我当前的查询:

$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 周围的逗号以找到发件人名称(LEFT JOIN users AS receivers ON messages.recipients(WITHOUT COMMAS ) = receivers.id。

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

有人知道我将如何处理这个问题吗?也许是子查询?非常感谢您的帮助。

【问题讨论】:

    标签: php mysql database


    【解决方案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 个(或零个)发件人。如果没有,并且某些邮件的发件人超过 1 个,那么您可能需要编辑 GROUP BY

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

    【讨论】:

    • 这看起来很棒,非常感谢。试着出去,我会回复你的!
    • ypercube,我现在正在阅读规范化,但您的意思是创建一个 MessageRecipient 表,您基本上可以在其中“标记”用户到消息?
    • 是的,因此您的 messages.recipients 字段将被该表中的许多行替换(消息中的每个收件人一个)
    • 这是一个更好的结构吗?我标准化了我的数据库。 pastebin.com/UGdKsx14
    • 是的。 messages_recipients 可以有一个复合主键 (messageid, userid)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 2014-03-02
    • 1970-01-01
    • 2011-12-23
    • 1970-01-01
    • 2018-06-02
    相关资源
    最近更新 更多