You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL GROUP BY实现会话收件箱:获取各对话最新消息

按对话线程获取最新消息的直接解法

你的核心问题是要把(SenderId=1, ReceiverId=2)和(SenderId=2, ReceiverId=1)视为同一个对话线程,同时取出每个线程的最新消息。原来的SQL因为分组维度不对,且无法保证取到最新数据,所以达不到效果。下面是两种更直接的解决方案:

方法一:使用窗口函数(推荐,现代SQL支持)

利用ROW_NUMBER()窗口函数,先给每个统一后的对话线程的消息按时间倒序编号,最新消息的编号为1,最后筛选出这条即可:

WITH thread_messages AS (
    SELECT 
        *,
        -- 按统一后的对话线程分组,按时间倒序排号
        ROW_NUMBER() OVER (
            PARTITION BY LEAST(SenderId, ReceiverId), GREATEST(SenderId, ReceiverId)
            ORDER BY ts DESC
        ) AS rn
    FROM message
    -- 过滤当前用户参与的对话
    WHERE SenderId = {current_user_id} OR ReceiverId = {current_user_id}
)
-- 取每个线程的第一条(最新)消息
SELECT Id, Body, ts, SenderId, ReceiverId
FROM thread_messages
WHERE rn = 1;

LEAST()和GREATEST()函数会把对话双方的ID按大小排序,不管谁发谁收,都能得到同一个线程标识(比如(1,2)和(2,1)都会变成1和2)。

方法二:分组关联(兼容老版本SQL)

如果你的数据库不支持窗口函数,可以先分组找到每个线程的最新时间,再关联原表获取对应消息:

SELECT m.*
FROM message m
INNER JOIN (
    SELECT 
        LEAST(SenderId, ReceiverId) AS user1,
        GREATEST(SenderId, ReceiverId) AS user2,
        MAX(ts) AS latest_ts
    FROM message
    WHERE SenderId = {current_user_id} OR ReceiverId = {current_user_id}
    GROUP BY user1, user2
) t ON LEAST(m.SenderId, m.ReceiverId) = t.user1 
   AND GREATEST(m.SenderId, m.ReceiverId) = t.user2
   AND m.ts = t.latest_ts;

如果同一个线程在同一时间有多条消息,这个查询会返回所有符合的记录,若只需一条,可以在子查询里同时取MAX(Id),并在关联条件里加上m.Id = t.latest_id。

原SQL的问题说明

你原来的GROUP BY SenderId, ReceiverId会把(1,2)和(2,1)分成两个独立分组,无法识别为同一个线程;同时SELECT *在标准SQL中不符合分组规则(仅部分数据库宽松模式允许),且无法保证取到分组内的最新消息,因为非聚合列的返回结果是不确定的。

内容的提问来源于stack exchange,提问作者digiadit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:27:23