SQL按ItemId分组优先取Flag=0行 每组仅保留一条数据
实现思路
核心逻辑是按ItemId分组后,组内优先保留Flag=0的行,避免直接聚合导致非聚合字段取值错误,以下是不同场景下的实现方案:
方案1:窗口函数法(通用,支持所有支持标准SQL的数据库)
适用于MySQL 8.0+、PostgreSQL、SQL Server、Hive、Spark SQL等绝大多数现代数据库,是兼容性最高的写法:
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY ItemId ORDER BY Flag ASC) AS group_rn FROM 你的表名 ) t WHERE group_rn = 1;
说明:
PARTITION BY ItemId将所有行按ItemId分组- 组内按
Flag升序排序,Flag=0的行永远排在同组Flag=1的行之前 - 取每组排序后序号为1的行,即可得到每个
ItemId优先级最高的完整行,ts等所有字段都保留原始行的正确值
如果同一个ItemId下存在多条Flag=0的行,可在排序规则后追加额外条件,比如要取ts最新的行,就将排序逻辑改为ORDER BY Flag ASC, ts DESC即可。
方案2:子查询关联法(兼容低版本不支持窗口函数的数据库)
如果你用的是MySQL 5.x这类不支持窗口函数的数据库,可以用分组取最小Flag再关联原表的方式实现:
SELECT t1.* FROM 你的表名 t1 INNER JOIN ( SELECT ItemId, MIN(Flag) AS priority_flag FROM 你的表名 GROUP BY ItemId ) t2 ON t1.ItemId = t2.ItemId AND t1.Flag = t2.priority_flag;
说明:先通过分组聚合拿到每个ItemId的最小Flag值(存在0就取0,不存在就取1),再用这个结果关联原表匹配对应行,就能拿到完整的正确数据。
方案3:PostgreSQL专用简化写法
PostgreSQL支持DISTINCT ON语法,可以更简洁的实现需求:
SELECT DISTINCT ON (ItemId) * FROM 你的表名 ORDER BY ItemId, Flag ASC;
说明:DISTINCT ON (ItemId)会保留每个ItemId分组的第一行,配合排序规则即可直接得到目标结果。
内容的提问来源于stack exchange,提问作者gorrch
相关产品推荐
相关产品推荐

