如何在SQL中基于姓名合并重复行并自动填充空缺列的值
SQL实现同姓名重复数据合并补全方案
核心实现逻辑是按姓名分组,利用聚合函数自动忽略NULL值的特性,提取每个字段分组内的非空值即可,以下是不同场景的写法:
主流数据库通用写法
MySQL、PostgreSQL、Spark SQL、Hive、SQL Server等绝大多数数据库都支持该方案:
SELECT 姓名, MAX(电话) AS 电话, MAX(邮箱) AS 邮箱, MAX(地址) AS 地址, -- 其余需要补全的字段均可以同理套用MAX函数 MAX(注册时间) AS 注册时间 FROM 你的客户表名称 GROUP BY 姓名;
说明:MAX/MIN函数在计算时会自动跳过NULL值,只要同一姓名分组下任意一行存在该字段的非空值,最终都会返回该值。如果同一姓名下同一个字段存在多个不同的非空值,可以根据业务需求调整逻辑:需要保留最早录入的值换用MIN函数,需要保留最新录入的值换用MAX函数,需要保留所有值可以用GROUP_CONCAT(MySQL)/STRING_AGG(PostgreSQL/SQL Server)拼接。
多值优先级自定义场景
如果你需要指定字段的取值优先级(比如优先取官方渠道录入的地址,其次取活动渠道录入的地址),可以用窗口函数实现:
WITH field_ranked AS ( SELECT *, -- 按你需要的优先级排序,非空值排在前面,也可以额外加渠道、录入时间等排序规则 ROW_NUMBER() OVER(PARTITION BY 姓名 ORDER BY CASE WHEN 电话 IS NOT NULL THEN 0 ELSE 1 END, CASE WHEN 邮箱 IS NOT NULL THEN 0 ELSE 1 END, CASE WHEN 地址 IS NOT NULL THEN 0 ELSE 1 END, 录入时间 DESC ) AS rn FROM 你的客户表名称 ) SELECT 姓名, 电话, 邮箱, 地址, 注册时间 FROM field_ranked WHERE rn = 1;
前置校验建议
合并前建议先排查同姓名下存在多个不同有效值的情况,避免误覆盖业务数据:
-- 排查同一姓名有多个不同电话的情况,其余字段可以同理调整 SELECT 姓名, COUNT(DISTINCT 电话) AS 不同电话数量 FROM 你的客户表名称 GROUP BY 姓名 HAVING COUNT(DISTINCT 电话) > 1;
如果存在姓名拼写不一致的情况(如同音字、多字漏字、大小写差异),需要先对姓名做标准化清洗(比如统一转小写、生成拼音相似度编码、模糊匹配纠错),再用标准化后的姓名字段分组。
内容的提问来源于stack exchange,提问作者Bryan
相关产品推荐
相关产品推荐

