我正在开发一个已经实现聊天功能的项目..数据库结构如下:
table 上聊天
id // auto-incrementing message id
created_by_id // user id of person who wrote this message
reply_to_id // id of FIRST message this message is in reply to (0 if new message)
creation_date // creation timestamp
text // message content
表格标签
chat_id // message id this row corresponds to
user_id // user id of person who is an audience of this message
is_unread // has the user read this message?
表用户
id // auto-incrementing id
name // name of user
示例数据
CHATS
1, {ME}, 0, {DATE}, 'This is a new message'
2, {HIM}, 1, {DATE}, 'This is a reply to the above message'
3, {HER}, 1, {DATE}, 'So is this one'
4, {HER}, 1, {DATE}, 'Another reply from HER'
5, {YOU}, 0, {DATE}, 'This is a different conversation'
TAGS
1, {ME}, 0 // ME, HIM and HER as audience, so 3 rows here
1, {HIM}, 0
1, {HER}, 0
2, {HIM}, 0 // ME, HIM and HER here as well
2, {ME}, 1
2, {HER}, 0
3, {HER}, 0 // ME, HIM and HER here as well
3, {ME}, 1
3, {HIM}, 1
4, {YOU}, 0 // YOU and HER as audience, so 2 rows here (ME and HIM should not see this)
4, {HER}, 1
这对于我们的目的来说效果很好。此外,这些表也在遗留应用程序中使用,因此结构无法更改..
现在我必须在两个 View 中显示这些消息..一个对话 View ..以及在单个对话 View 中显示一条消息..
对于对话 View ,我需要设计一个 SQL 查询,使每一行包含以下内容(不进行 N 个子查询):
- 初始聊天 ID(
id
,其中reply_to_id = 0
) - 最近最多的聊天 ID(对话中最大的
reply_to_id
) - 最近最多的聊天消息
- 消息收件人列表 (
tag.chat_id = chat.id
)
有人可以帮助我或指导我找到解决方案吗?具体来说,我需要以下方面的指导:
- 我可以通过
IF(reply_to_id = 0,id,reply_to_id)找到消息的对话ID
..我也可以按它分组以返回单个对话行..但是我可以不检索该组中的最新行.. - 同样重要的是,我需要找到此消息的所有收件人..作为数组甚至逗号分隔的字符串..但我不知道如何..
- 我稍后需要实现一个分页解决方案..我非常确定这也将决定如何编写查询..
谢谢..
敬畏
编辑
这是我现在正在使用的查询..它工作正常,除了我无法在没有单独查询的情况下找到对话的所有收件人..
SELECT * FROM (
SELECT
IF (c.reply_to_id = 0, c.id, c.reply_to_id) as conv_id,
c.*,
t.*
FROM chats AS c
INNER JOIN tags AS t
ON t.chat_id = c.id OR t.chat_id = c.reply_to_id
WHERE
t.user_id = {ME}
ORDER BY
creation_date DESC
) AS data
GROUP BY conv_id
LIMIT 10 OFFSET 0
我怎样才能在此查询中找到收件人列表?
最佳答案
假设您的查询确实为每次转化提供了一行,那么您可以使用 GROUP_CONCAT 函数来获取该系列中最后一次聊天的收件人:
SELECT {other fields}, GROUP_CONCAT(tags.user_id) AS list_of_recipients
FROM
{your query}
) AS conversation
INNER JOIN tags on conversation.conv_id=tags.chat_id
GROUP BY conversation.conv_id
但是,我真的不知道如何很好地获取所有其他字段(尽管可能)。
这是我编写但尚未测试的替代方案。基本想法是我想找到对话中的第一个和最后一个 chat_id,并将中间的所有内容删除。因此,我创建了pair1,用于识别链中的第一对,创建pair2,用于识别椅子中的最后一对。然后我将第一对中的第二个聊天加入到第二对中的第一个聊天中。接下来,我从这个新的pair3中选择第一个chat_id确实是初始聊天的行,最后一个chat_id确实是最后一个。然后,我通过一个联接选取聊天的正文,并通过另一个联接选取所有收件人。通过对第一个和最后一个聊天 ID 进行分组,我可以将所有收件人连接到一个值中。我使用 FIRST() 来廉价地获取文本。如果您需要将收件人列表加入到用户表中,您可能需要这样做,而不是使用 GROUP BY 和 GROUP_CONCAT。或者,如果您想要一个名称列表,您可以加入用户表,然后对他们的名称执行 GROUP_CONCAT。
HTH
SELECT initial_chat_id, most_recent_chat_id,
FIRST(most_recent_chat.text),
GROUP_CONCAT(tags.user_id) AS list_of_recipients_most_recent_chat
FROM
(
SELECT prev1_id as initial_chat_id, max(IF(next2_id IS NULL,prev1_id,next2_id)) as most_recent_chat_id
FROM
(
(SELECT prev_chat.id AS prev1_id, prev_chat.reply_to_id as prev1_reply_id,
next_chat.id AS next1_id
FROM chats prev_chat LEFT JOIN
chats next_chat on prev_chat.id=next_chat.reply_to_id) AS pair1
LEFT JOIN
(SELECT prev_chat.id AS prev2_id, prev_chat.reply_to_id as prev2_reply_id,
next_chat.id AS next2_id
FROM chats prev_chat LEFT JOIN
chats next_chat on prev_chat.id=next_chat.reply_to_id) AS pair2
ON pair1.next_id=pair2.prev_id) as pair3
WHERE
prev1_reply_id IS NULL AND next2_id IS NULL) AS conversation
INNER JOIN tags ON conversation.most_recent_chat_id=tags.chat_id
INNER JOIN chats most_recent_chat ON conversation.most_recent_chat_id=most_recent_chat.id
GROUP BY initial_chat_id, most_recent_chat_id, tags.chat_id;
关于mysql - 单个 SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26499078/