mysql - 单个 SQL 查询

标签 mysql sql

我正在开发一个已经实现聊天功能的项目..数据库结构如下:

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/

相关文章:

python - 在 mysql 上使用 pandas 和 sqlalchemy 将元组保存到数据库

php - 使用多个 where 子句进行删除非常慢

php - 将复选框值插入数据库

php - 使用 <input type ="button"> 提交表单

mysql - 在 MySQL 中创建一个索引是另一个索引的子集

MySQL:是否可以在同一个结果表中显示聚合数据1和聚合数据2?

PHP:以递归方式填充数组

mysql - 如果无需 JOIN 就可以从多个表中进行选择,为什么还要使用 JOIN?

mysql - 唯一名称(第 1 列、第 2 列)

mysql - MySQL 中的唯一值组合