我正在创建一个类似于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”;。
任何人都知道如何处理这个问题?一个子查询可能吗?我非常感谢你的帮助。
答案 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
中间表规范化您的结构。