
本文详解如何在 SQL 中实现“按 domain 去重,同时保留每组中 domain_date 最大的那条完整记录”,并进一步限制结果为最新的 5 条,适用于日志、域名监控、用户行为等场景。
本文详解如何在 SQL 中实现“按 domain 去重,同时保留每组中 domain_date 最大的那条完整记录”,并进一步限制结果为最新的 5 条,适用于日志、域名监控、用户行为等场景。
在实际数据库查询中,常遇到这样的需求:既要消除某字段(如 domain)的重复值,又要确保保留该组中按时间(如 domain_date)最新的那条完整记录。此时直接使用 SELECT DISTINCT domain, domain_date 是无效的——因为 DISTINCT 作用于所有 SELECT 列的组合,只要任一列值不同即视为不同行,无法实现“按 domain 分组取最新”的语义。
正确解法是采用 分组聚合 + 关联回查(self-join) 的经典模式:
✅ 步骤一:用 GROUP BY 获取每个 domain 的最新时间
SELECT domain, MAX(domain_date) AS latest_date FROM Domains GROUP BY domain;
该查询返回每个唯一 domain 对应的最新 domain_date,实现了逻辑去重与时间筛选。
✅ 步骤二:关联原表,取出完整记录
仅知道时间还不够,我们需要原始记录中的 domain_status 等字段。因此需将上述结果作为子查询,与原表 INNER JOIN,精确匹配 domain 和 latest_date:
SELECT d1.domain, d1.domain_date, d1.domain_status
FROM Domains d1
INNER JOIN (
SELECT domain, MAX(domain_date) AS latest_date
FROM Domains
GROUP BY domain
) d2
ON d1.domain = d2.domain AND d1.domain_date = d2.latest_date;
⚠️ 注意:若存在同一 domain 的多条记录具有完全相同的
MAX(domain_date)(例如毫秒级时间相同或未记录毫秒),此查询可能返回多行。如需严格保证每 domain 仅一行,可在子查询中加入ROW_NUMBER()窗口函数进行二次去重(见进阶方案)。
✅ 步骤三:按最新时间倒序排列,并限制前 5 条
在最终结果上添加 ORDER BY domain_date DESC 和分页子句即可:
SELECT d1.domain, d1.domain_date, d1.domain_status
FROM Domains d1
INNER JOIN (
SELECT domain, MAX(domain_date) AS latest_date
FROM Domains
GROUP BY domain
) d2
ON d1.domain = d2.domain AND d1.domain_date = d2.latest_date
ORDER BY d1.domain_date DESC
LIMIT 5; -- MySQL / PostgreSQL
-- SQL Server 用户请用: TOP 5
-- Oracle 用户可使用: FETCH FIRST 5 ROWS ONLY(Oracle 12c+)
? 进阶建议:处理时间相同导致的重复
若业务要求绝对唯一(如避免因并发插入造成同 domain 同秒级时间),推荐使用窗口函数替代聚合:
SELECT domain, domain_date, domain_status
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY domain ORDER BY domain_date DESC, id DESC) AS rn
FROM Domains
) ranked
WHERE rn = 1
ORDER BY domain_date DESC
LIMIT 5;
此写法更健壮:PARTITION BY domain 实现分组,ORDER BY domain_date DESC, id DESC 确保时间相同时取主键更大的记录(即更晚插入),rn = 1 精确取每组首行。
✅ 总结
-
DISTINCT无法解决“单列去重 + 多列取最新”的需求; - 核心思路是:先分组聚合得关键标识(如最大时间),再通过 JOIN 恢复完整行;
- 生产环境建议优先使用
ROW_NUMBER()窗口函数方案,语义清晰、可控性强、兼容主流数据库; - 记得为
domain和domain_date字段建立联合索引(如INDEX idx_domain_date (domain, domain_date)),大幅提升查询性能。










