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

PostgreSQL:按name列去重并保留最高ts_rank值的实现方案

解决按name去重并保留最高rank的问题

嘿,我懂你的需求啦——现在你的查询会返回多个相同name的结果,你想要每个name只留下对应rank最高的那一行对吧?这在PostgreSQL里有两种实用的实现方式,我给你详细说说:

方法一:用PostgreSQL专属的DISTINCT ON(简洁高效)

DISTINCT ON是PostgreSQL的语法糖,能快速实现「按指定列去重,保留每组排序后第一行」的需求,特别适配你的场景:

SELECT DISTINCT ON (name) 
       name,
       ts_rank(to_tsvector(name), query) + ts_rank(to_tsvector(content), query2) AS rank
FROM users
INNER JOIN microposts ON users.id = microposts.user_id,
     plainto_tsquery('re') query,
     plainto_tsquery('comics') query2
WHERE users.name @@ query OR microposts.content @@ query2
ORDER BY name, rank DESC;

重点说明:

  • DISTINCT ON (name):明确指定按name列去重,每组仅保留第一行数据
  • ORDER BY name, rank DESC:必须先按去重列排序,再按rank降序排列——这样每组里rank最高的行会排在第一位,刚好被DISTINCT ON保留下来

方法二:用窗口函数ROW_NUMBER()(通用兼容型)

如果你需要兼容其他数据库,或者后续有更复杂的分组逻辑,窗口函数是更通用的选择:

WITH ranked_results AS (
    SELECT 
        name,
        ts_rank(to_tsvector(name), query) + ts_rank(to_tsvector(content), query2) AS rank,
        ROW_NUMBER() OVER (PARTITION BY name ORDER BY rank DESC) AS rn
    FROM users
    INNER JOIN microposts ON users.id = microposts.user_id,
         plainto_tsquery('re') query,
         plainto_tsquery('comics') query2
    WHERE users.name @@ query OR microposts.content @@ query2
)
SELECT name, rank
FROM ranked_results
WHERE rn = 1
ORDER BY rank DESC;

重点说明:

  • PARTITION BY name:按name分组,给每组内的行单独编号
  • ORDER BY rank DESC:每组内按rank降序编号,最高rank的行编号为1
  • 最后筛选rn = 1的行,就得到了每个name对应的最高rank记录

两种方法都能满足你的需求,DISTINCT ON在PostgreSQL里性能更优、写法更简洁;窗口函数则适配性更强,适合复杂场景。你可以根据自己的实际情况选择~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:26:40