单个SQL查询

时间:2014-10-22 01:36:33

标签: mysql sql

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

表格聊天

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

这适用于我们的目的..此外,这些表也用于遗留应用程序,因此结构无法更改..

现在我必须在两个视图中显示这些消息..会话视图..以及单个会话视图中的消息..

对于会话视图,我需要设计一个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 ..我也可以将其分组以返回单个会话行..但是我无法检索此组中的最新行..
  • 同样重要,我需要找到此消息的所有收件人..作为数组甚至是逗号分隔的字符串..但我不知道如何...
  • 我需要稍后实现一个分页解决方案..我很确定这也将决定如何编写查询..

感谢..

awesim


修改

这是我现在正在使用的查询..它工作正常,除了我找不到对话的所有收件人而没有单独的查询..

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

如何在此查询中找到收件人列表?

1 个答案:

答案 0 :(得分:3)

假设您的查询确实为每次转化提供了一行,那么您可以使用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,然后将所有的chat_id放在中间。所以我创建了用于识别链中第一对的pair1,以及用于识别椅子中最后一对的pair2。然后我加入第一对中的第二个聊天到第二对中的第一个聊天。接下来,我从这个新的pair3中选出第一个chat_id确实是初始聊天的行,最后一个chat_id确实是最后一个。然后,我通过联接获取聊天的正文,并通过另一个联接获取所有收件人。对第一个和最后一个聊天ID进行分组可以让我将所有收件人连接成一个值。我使用FIRST()以便宜的方式获取文本。如果您需要将收件人列表加入users表,您可能希望这样做而不是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;