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

SQL按分组最大值过滤近重复行 查询用户最高技能等级记录

问题场景

现有3张数据库表,所有存量历史数据因监管要求不可删除:

  • dbo.skills:技能维度表,主键为skill_ID_PK
  • dbo.people:用户维度表,主键为user_ID_PK
  • dbo.skillHistory:技能持有/变更历史表,通过外键关联上述两张表的主键,存储用户所有技能的全量历史记录,存在同一用户同一技能多次等级变更的重复行
    需求为按用户ID+技能ID维度分组,返回每个用户对应每项技能最高等级对应的完整记录,过滤同维度下等级更低的冗余历史行。
最优实现方案

优先使用窗口函数实现,该写法仅需扫描一次历史表,执行效率远高于分组自连接等传统写法,且全程为只读操作,完全符合合规要求,兼容SQL Server、MySQL 8.0+、PostgreSQL等所有支持窗口函数的主流数据库。

WITH history_ranked AS (
    SELECT
        *,
        ROW_NUMBER() OVER (
            PARTITION BY user_ID_PK, skill_ID_PK
            ORDER BY Skill_Level DESC, -- 按技能等级倒序,最高等级记录排分区首位
                    record_create_time DESC -- 若同用户同技能存在多条相同最高等级记录,取最新生成的一条,可根据业务实际时间字段调整排序规则
        ) AS row_rank
    FROM dbo.skillHistory
)
-- 需要关联用户、技能维度信息时直接关联维度表即可,不需要可以去掉join部分
SELECT
    h.*,
    p.user_name, -- 按需取people表字段
    s.skill_name -- 按需取skills表字段
FROM history_ranked h
LEFT JOIN dbo.people p ON h.user_ID_PK = p.user_ID_PK
LEFT JOIN dbo.skills s ON h.skill_ID_PK = s.skill_ID_PK
WHERE h.row_rank = 1;

低版本兼容写法

如果数据库版本不支持窗口函数(如MySQL 5.x、SQL Server 2005以下版本),可以使用分组关联的写法,性能弱于窗口函数版本,数据量较大时不推荐:

SELECT h.*
FROM dbo.skillHistory h
INNER JOIN (
    SELECT
        user_ID_PK,
        skill_ID_PK,
        MAX(Skill_Level) AS max_skill_level
    FROM dbo.skillHistory
    GROUP BY user_ID_PK, skill_ID_PK
) t ON h.user_ID_PK = t.user_ID_PK
    AND h.skill_ID_PK = t.skill_ID_PK
    AND h.Skill_Level = t.max_skill_level;

注意:该兼容写法在同用户同技能存在多条相同最高等级记录时,会返回所有匹配行,需要只取单条的话可以追加一层最大记录时间的关联条件过滤。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:21:43