0

我目前正在为查询而苦苦挣扎,需要一些帮助。

我有两张桌子:

messages {
   ts_send,
   message,
   conversations_id
}

conversations {
   id
}

我想从每个对话中选择具有最新 ts_send 的消息。因此,如果我有 3 个对话,我最终会收到 3 条消息。

我开始编写以下查询,但我很困惑如何比较每个对话的 max(ts_send)。

SELECT c.id, message, max(ts_send) FROM messages m
JOIN conversations c ON m.conversations_id = c.id
WHERE c.id IN ('.implode(',', $conversations_ids).')
GROUP by c.id
HAVING max(ts_send) = ?';

也许查询通常是错误的,只是想分享我的尝试。

问候克里斯蒂安

4

5 回答 5

3

MySql 对 JOIN 的优化比相关子查询好得多,所以我将介绍连接方法。

第一步是获得ts_send每个对话的最大值:

SELECT  conversations_id, MAX(ts_send) AS ts_send
FROM    messages
GROUP BY conversations_id;

然后,您需要将JOIN其返回到消息表以获取实际消息。conversation_id 和 MAX(ts_send) 上的连接确保每个对话只返回最新消息:

SELECT  messages.conversations_id,
        messages.message,
        Messages.ts_send
FROM    messages
        INNER JOIN
        (   SELECT  conversations_id, MAX(ts_send) AS ts_send
            FROM    messages
            GROUP BY conversations_id
        ) MaxMessage
            ON MaxMessage.conversations_id = messages.conversations_id
            AND MaxMessage.ts_send = messages.ts_send;

以上内容应该可以为您提供所需的内容,除非您还需要在没有消息的情况下返回对话。在这种情况下,您将需要从conversations上述查询中选择并 LEFT JOIN:

SELECT  conversations.id,
        COALESCE(messages.message, 'No Messages') AS Message,
        messages.ts_send
FROM    conversations
        LEFT JOIN
        (   SELECT  messages.conversations_id,
                    messages.message,
                    Messages.ts_send
            FROM    messages
                    INNER JOIN
                    (   SELECT  conversations_id, MAX(ts_send) AS ts_send
                        FROM    messages
                        GROUP BY conversations_id
                    ) MaxMessage
                        ON MaxMessage.conversations_id = messages.conversations_id
                        AND MaxMessage.ts_send = messages.ts_send
        ) messages
            ON messages.conversations_id = conversations.id;

编辑

选择所有对话而不管它们是否有消息的后一种选项会更好地实现如下:

SELECT  conversations.id,
        COALESCE(messages.message, 'No Messages') AS Message,
        messages.ts_send
FROM    conversations
        LEFT JOIN messages
            ON messages.conversations_id = conversations.id
        LEFT JOIN
        (   SELECT  conversations_id, MAX(ts_send) AS ts_send
            FROM    messages
            GROUP BY conversations_id
        ) MaxMessage
            ON MaxMessage.conversations_id = messages.conversations_id
            AND MaxMessage.ts_send = messages.ts_send
WHERE   messages.ts_send IS NULL
OR      MaxMessage.ts_send IS NOT NULL;

在此感谢spencer7593,他提出了上述解决方案。

于 2013-08-14T18:59:34.183 回答
1

如果您只想ts_send从每个 unique中获取最大的conversations_id值,可以使用以下代码:

SELECT *
  FROM messages
 WHERE CONCAT(conversations_id, '_', ts_send) IN (   SELECT CONCAT(conversations_id, '_', MAX(ts_send))
                                                       FROM messages
                                                   GROUP BY conversations_id );

SQL小提琴

这段代码所做的是,它创建了对conversations_id, 以及最大的ts_send. 然后将其与整个表中的所有对进行比较。

于 2013-08-14T17:19:40.200 回答
1
SELECT c.id, m.message, m.ts_send
FROM conversations c LEFT JOIN messages m 
    ON c.id = m.conversations_id
WHERE m.ts_send = 
    (SELECT MAX(m2.ts_send) 
    FROM messages m2 
    WHERE m2.conversations_id = m.conversations_id)

LEFT JOIN 确保每个对话都有一行,无论它是否有消息。如果您的模型无法做到这一点,则可能没有必要。在这种情况下:

SELECT m.conversations_id, m.message, m.ts_send
FROM messages m 
WHERE m.ts_send = 
    (SELECT MAX(m2.ts_send) 
    FROM messages m2 
    WHERE m2.conversations_id = m.conversations_id)
于 2013-08-14T17:22:05.287 回答
1
SELECT c.id, m.message, m.ts_send
FROM
messages m, conversations c,
(SELECT conversations_id, MAX(ts_send) as ts_send 
from messages 
group by conversations_id) s
where s.conversations_id=m.conversations_id and s.ts_send=m.ts_send and 
c.id=m.conversations_id
于 2013-08-14T17:29:19.923 回答
0

我想这就是你所说的。

mysql> create table messages (ts_send int, message char(30), id int);
Query OK, 0 rows affected (0.01 sec)

mysql> create table conversations (id int);
Query OK, 0 rows affected (0.01 sec)

现在一些数据。

    mysql> insert into conversations values ( 1), (2), (3), (4);
    Query OK, 4 rows affected (0.00 sec)
    Records: 4  Duplicates: 0  Warnings: 0


    mysql> insert into messages values ( 4, 'abc', 1 ), 
(5, 'pqr', 1), 
(4, 'abc', 2), 
(5, 'abc', 3), 
(6, 'abc', 4);
    Query OK, 5 rows affected (0.01 sec)
    Records: 5  Duplicates: 0  Warnings: 0

然后是查询。

    mysql> select messages.id, message, ts_send 
from messages 
where ROW(id, ts_send) in 
(select messages.id, max(ts_send) 
from messages, conversations 
where messages.id = conversations.id group by id);
    +------+---------+---------+
    | id   | message | ts_send |
    +------+---------+---------+
    |    1 | pqr     |       5 |
    |    2 | abc     |       4 |
    |    3 | abc     |       5 |
    |    4 | abc     |       6 |
    +------+---------+---------+
    4 rows in set (0.00 sec)


     mysql> 

对?

*对此进行了编辑,以反映 Marty McVry 的评论。

于 2013-08-14T17:19:25.913 回答