如何删除SQL表单行内的重复值?以deployment表为例
优化SQL行内重复ID去重并合并的方案
问题回顾
你需要对deployment表按日期分组,将每行task1-task4列中的人员ID去重后合并为逗号分隔的列表,现有自定义函数实现,但想寻找更优方案。
现有方案的问题
你的自定义函数存在几个明显缺陷:
- 分隔符不一致:用
concat拼接ID时使用;,但string_split却用,拆分,导致无法正确拆分ID,最终结果会把整个拼接字符串当作单个元素 - 未处理NULL值:若某个task列为NULL,拼接后会出现连续的
;,拆分后会引入空字符串 - 性能瓶颈:标量函数是逐行执行的,当表数据量较大时,性能远低于集合式操作
更优实现方案
方案1:使用UNPIVOT(SQL Server 2005+支持)
通过UNPIVOT将多列的task数据转为行数据,再按日期分组去重后用STRING_AGG合并,这是最简洁高效的集合式操作:
SELECT date, STRING_AGG(DISTINCT task_id, ', ') AS ids FROM deployment UNPIVOT ( task_id FOR tasks IN (task1, task2, task3, task4) ) AS unpivoted GROUP BY date;
方案2:使用CROSS APPLY VALUES(兼容更多SQL Server版本)
如果你的SQL Server版本不支持UNPIVOT,可以用CROSS APPLY结合VALUES实现列转行,效果一致:
SELECT d.date, STRING_AGG(DISTINCT v.task_id, ', ') AS ids FROM deployment d CROSS APPLY ( VALUES (task1), (task2), (task3), (task4) ) AS v(task_id) WHERE v.task_id IS NOT NULL -- 过滤NULL值 GROUP BY d.date;
方案优势
- 性能更优:集合式操作避免了逐行调用函数的开销,数据量越大优势越明显
- 逻辑清晰:通过列转行+分组去重+合并的流程完成需求,代码可读性高
- 自动处理异常:自动过滤NULL值,不会引入空字符串或错误拆分的问题
- 无需维护函数:不需要额外维护自定义函数,降低代码复杂度
内容的提问来源于stack exchange,提问作者Minh Nghĩa Nguyễn
相关产品推荐
相关产品推荐

