SQL去重需求:指定列重复时保留首行并返回全列
解决方案
MySQL/MariaDB 实现方式
用ROW_NUMBER()窗口函数按指定列分组,给每组的行编号,只取每组第一行。如果不需要特定排序逻辑,用(SELECT 1)让数据库返回任意首行即可:
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY DeviceId, TransactionId, IndetId, Datetime, SalesId ORDER BY (SELECT 1)) AS row_num FROM Foo ) AS temp WHERE row_num = 1;
要是需要按特定规则选首行(比如最新时间、最大Quantity),把(SELECT 1)换成对应列就行,比如ORDER BY Datetime DESC。
SQL Server 实现方式
逻辑和MySQL一致,用CTE加窗口函数:
WITH RankedRows AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY DeviceId, TransactionId, IndetId, Datetime, SalesId ORDER BY (SELECT NULL)) AS row_num FROM Foo ) SELECT * FROM RankedRows WHERE row_num = 1;
PostgreSQL 实现方式
除了通用的窗口函数写法,还能用上PostgreSQL专属的DISTINCT ON语法,更简洁:
-- 通用窗口函数写法 SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY DeviceId, TransactionId, IndetId, Datetime, SalesId ORDER BY (SELECT 1)) AS row_num FROM Foo ) AS temp WHERE row_num = 1; -- PostgreSQL专属简洁写法 SELECT DISTINCT ON (DeviceId, TransactionId, IndetId, Datetime, SalesId) * FROM Foo ORDER BY DeviceId, TransactionId, IndetId, Datetime, SalesId;
DISTINCT ON会保留每组排序后的第一行,ORDER BY必须先写分组列,后面可追加其他排序规则。
关键注意点
- 要是你需要“首行”是符合特定逻辑的行(比如最早创建时间、最大Quantity),一定要在
ORDER BY里明确指定对应列,不然数据库返回的首行是随机的。 - 别直接用
GROUP BY,因为它要求非聚合列都得在分组条件里,没法返回所有列,满足不了需求。
内容的提问来源于stack exchange,提问作者tony
相关产品推荐
相关产品推荐

