如何为每个对话选择上一条消息?

时间:2013-04-26 11:19:15

标签: mysql sql group-by greatest-n-per-group

以下是我的数据库的样子:

表:conversations

+----+--------+--------+
| id | user_1 | user_2 |
+----+--------+--------+
| 1  | 1      | 2      |
| 2  | 2      | 3      |
| 3  | 1      | 3      |
+----+--------+--------+

表:messages

+----+--------------+------+
| id | conversation | text |
+----+--------------+------+
| 1  | 1            | hej  |
| 2  | 1            | test |
| 3  | 2            | doh  |
| 4  | 2            | hi   |
| 5  | 3            | :)   |
| 6  | 3            | :D   |
+----+--------------+------+

然后当我运行以下查询时:

SELECT
    *
FROM `messages`
INNER JOIN `conversations`
    ON `conversations`.`id` = `messages`.`convesations`
GROUP BY `conversations`.`id`
ORDER BY `messages`.`id` DESC

然后我从messages获取了这些:

+----+--------------+------+
| id | conversation | text |
+----+--------------+------+
| 1  | 1            | hej  |
| 3  | 2            | doh  |
| 5  | 3            | :)   |
+----+--------------+------+

但是,是否有可能这样做,以便我从该组中获取具有最高messages.id的消息,而不是最低的消息?

编辑:这是我想要的输出messages

+----+--------------+------+
| id | conversation | text |
+----+--------------+------+
| 2  | 1            | test |
| 4  | 2            | hi   |
| 6  | 3            | :D   |
+----+--------------+------+

因为那些messages位于同一conversation id {。}}。

5 个答案:

答案 0 :(得分:7)

SELECT  *
FROM    conversations c
JOIN    messages m
ON      m.id =
        (
        SELECT  id
        FROM    messages mi
        WHERE   mi.conversation = c.id
        ORDER BY
                mi.conversation DESC, mi.id DESC
        LIMIT 1
        )

messages (conversation, id)上创建一个索引,以便快速工作。

答案 1 :(得分:4)

您只需使用这样的嵌套查询:

SELECT * FROM Messages 
WHERE ID IN(
            SELECT Max(m.ID) FROM Messages m
            INNER JOIN conversations c
                    ON c.id = m.conversation
              GROUP BY m.conversation
           );

输出:

| ID | CONVERSATION | TEXT |
----------------------------
|  2 |            1 | test |
|  4 |            2 |   hi |
|  6 |            3 |   :D |

如果您想要来自两个表的数据,请尝试:

SELECT * FROM Messages m
    JOIN conversations c
      ON c.id = m.conversation
WHERE m.ID IN (
                 SELECT MAX(ID) FROM Messages 
                 GROUP BY conversation
              )
GROUP BY m.conversation;

输出:

| ID | CONVERSATION | TEXT | USER_1 | USER_2 |
----------------------------------------------
|  2 |            1 | test |      1 |      2 |
|  4 |            2 |   hi |      2 |      3 |
|  6 |            3 |   :D |      1 |      3 |

See this SQLFiddle

答案 2 :(得分:1)

我认为你只有一个不正确的表连接:

SELECT *
FROM `messages`
INNER JOIN `conversations`
    ON `conversations`.`id` = `messages`.`conversation`
GROUP BY `conversations`.`id`
ORDER BY `messages`.`id` DESC

修改

你可以试试这个:

SELECT *
FROM `messages`
WHERE `messages`.`id` IN (
    SELECT MAX(id)
    FROM messages
    GROUP BY conversation
)

答案 3 :(得分:1)

您正在使用错误的列进行加入。对话中的“Id”不能等于消息中的“Id”。

我很瘦,表格中的'对话'是'id_conversation'对吗?

所以,如果我理解得很好:

SELECT *
FROM messages
INNER JOIN conversations
    ON conversations.id = messages.conversation
GROUP BY conversations.id
ORDER BY messages.id DESC

答案 4 :(得分:1)

有两种不同的方法:

这种方法依赖于MySQL中已知但未记录的行为,其中分组查询中返回的未聚合的未分组值是排序顺序中的第一个 - 它很快,但不应被视为可靠:

SELECT * FROM 
(SELECT * FROM messages 
ORDER BY conversation, id desc) a
GROUP BY conversation

或者,一种始终可靠的方法:

SELECT m.*, c.user_1, c.user_2 FROM messages m
 JOIN (select conversation, max(id) max_id from messages group by conversation) l
   ON m.id = l.max_id
 JOIN conversations c
   ON c.id = m.conversation
GROUP BY conversation

SQLFiddle here