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

如何在带UNION的SQL语句中按dm表id倒序排序?

解决按私信ID倒序排列对话对象的问题

这个问题我碰到过好几次,核心原因是你要用来排序的id字段并没有出现在UNION查询的最终结果集中,而且UNION会合并去重,直接加ORDER BY id自然会报错。这里给你两种实用的修改方案,都能实现按最后一条消息的ID倒序(也就是最新对话在前)的需求:

方案一:使用分组+最大ID排序

这种方法兼容性好,几乎所有SQL数据库都支持:

SELECT contact
FROM (
    -- 先把所有接收和发送的消息记录都列出来,保留ID
    SELECT `from` AS contact, id
    FROM dm
    WHERE `to` = '$username'
    UNION ALL
    SELECT `to` AS contact, id
    FROM dm
    WHERE `from` = '$username'
) AS all_messages
-- 按对话对象分组,取每个对象的最新消息ID
GROUP BY contact
ORDER BY MAX(id) DESC;

关键点说明:

  1. 用UNION ALL替代UNION:因为我们需要保留所有相关记录来计算每个对话对象的最新消息ID,UNION会自动去重,反而会丢失有用的ID信息。
  2. 用MAX(id)排序:每个对话对象的最大ID就是和他最后一次对话的消息ID,按这个值倒序就能实现最新对话优先。
  3. 注意反引号:from是SQL的保留关键字,作为列名时必须用反引号(MySQL)或双引号(PostgreSQL等)包裹,避免语法错误。

方案二:使用窗口函数(适合MySQL 8+、PostgreSQL等)

如果你的数据库支持窗口函数,这种写法更清晰,也更容易扩展:

SELECT contact
FROM (
    SELECT 
        -- 统一把对话对方的用户名命名为contact
        CASE 
            WHEN `to` = '$username' THEN `from` 
            ELSE `to` 
        END AS contact,
        id,
        -- 按对话对象分组,每组内按ID倒序排名
        ROW_NUMBER() OVER (
            PARTITION BY CASE WHEN `to` = '$username' THEN `from` ELSE `to` END 
            ORDER BY id DESC
        ) AS rn
    FROM dm
    -- 筛选所有和当前用户相关的消息
    WHERE `to` = '$username' OR `from` = '$username'
) AS ranked_messages
-- 只保留每个对话对象的最新一条记录
WHERE rn = 1
ORDER BY id DESC;

关键点说明:

  • ROW_NUMBER()窗口函数会给每个对话对象的消息按ID倒序编号,rn=1就是该对象的最新消息。
  • 最终按这条最新消息的ID倒序排列,就能实现需求。

重要提醒:SQL注入风险

你当前直接把$username拼接到SQL语句里,存在严重的SQL注入风险!建议改用参数化查询(比如Java的PreparedStatement、PHP的PDO预处理等),把$username作为参数传入,而不是直接拼接字符串。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:02:42