基于单字段去重且保留首次行的所有表列查询最简方法
单字段去重保留首行全列查询方案
首先明确前提:SQL不存在内置的行先后顺序,你需要提前指定一个可唯一确定行出现顺序的字段(如自增主键、数据插入时间戳等),才能准确定位“首次出现”的行。
以下是不同场景下的实现方案:
通用方案(支持所有支持窗口函数的数据库,如MySQL 8.0+、PostgreSQL、SQL Server、Spark SQL等)
核心逻辑是用ROW_NUMBER()窗口函数对目标去重字段分组,按行顺序字段排序后取每组的第一行:
-- 把Col_A替换为你要去重的字段,create_time替换为你用来判断行先后的排序字段,你的表名替换为实际表名 WITH ranked_data AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY Col_A ORDER BY create_time ASC) AS row_rank FROM 你的表名 ) -- 支持EXCEPT语法的数据库可以直接排除行号列,不需要手动写所有列名 SELECT * EXCEPT(row_rank) FROM ranked_data WHERE row_rank = 1;
如果你的数据库不支持EXCEPT语法,又不想手动写100多个列名,可以用系统表快速生成需要查询的列名:
- MySQL查询:
SELECT GROUP_CONCAT(COLUMN_NAME SEPARATOR ', ') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '你的表名'; - PostgreSQL查询:
SELECT string_agg(column_name, ', ') FROM information_schema.columns WHERE table_name = '你的表名';
把查询得到的列名字符串替换上面SQL的* EXCEPT(row_rank)部分即可。
低版本MySQL(5.x及以下,不支持窗口函数)方案
可以用分组取首次出现的标识值再关联原表的方式实现:
SELECT t1.* FROM 你的表名 t1 INNER JOIN ( -- 取每个Col_A对应的最小排序字段值,即首次出现的行的标识 SELECT Col_A, MIN(create_time) AS first_create_time FROM 你的表名 GROUP BY Col_A ) t2 ON t1.Col_A = t2.Col_A AND t1.create_time = t2.first_create_time;
提示:如果同一个Col_A下存在多个相同create_time的行,可以把排序字段换成自增主键,避免返回重复行。
内容的提问来源于stack exchange,提问作者SAURABH RANA
相关产品推荐
相关产品推荐

