从聚合函数定义的列中选择值

时间:2013-08-14 17:07:29

标签: mysql sql mysqli

我目前正在努力处理查询并需要一些帮助。

我有两张桌子:

messages {
   ts_send,
   message,
   conversations_id
}

conversations {
   id
}

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

我开始编写以下查询,但我很困惑如何比较每次会话的最大值(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) = ?';

一般来说,查询可能是错误的,只是想分享我的尝试。

关心基督徒

5 个答案:

答案 0 :(得分: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,他提出了上述解决方案。

答案 1 :(得分:1)

如果您只想获得每个唯一ts_send中最大的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-fiddle

此代码的作用是,它会创建conversations_id对和最大ts_send对。然后将其与整个表中的所有对进行比较。

答案 2 :(得分: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)

答案 3 :(得分: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

答案 4 :(得分: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的评论。