SQL对比两列数据 同值返回单行异值拆分为多行的实现方法
需求背景
存在员工表emp,表中存储员工姓名、两个联系号码字段,样例数据如下:
emp_name contact1 contact2 Harish 123 123 Manish 345 567 Ganesh 678 678
输出规则
- 若同一员工的
contact1与contact2值相同,仅返回1行记录,内容为员工姓名+对应联系方式 - 若两个联系号码值不同,拆分为2行返回,每行分别对应员工姓名+其中一个联系方式
期望输出结果:
emp_name contact Harish 123 Ganesh 678 Manish 345 Manish 567
可落地的SQL实现方案
以下写法覆盖主流数据库场景,可根据自身使用的数据库选型:
- 通用兼容写法(全数据库支持,无版本/语法限制)
利用UNION ALL拼接结果集,第二部分仅取两个号码不相等的记录,天然避免重复行,性能最优:SELECT emp_name, contact1 AS contact FROM emp UNION ALL SELECT emp_name, contact2 AS contact FROM emp WHERE contact1 <> contact2 -- 若字段允许为NULL,可补充空值判断逻辑: -- OR (contact1 IS NULL AND contact2 IS NOT NULL) -- OR (contact1 IS NOT NULL AND contact2 IS NULL) ORDER BY emp_name, contact; - 行转列函数写法(支持
UNPIVOT语法的数据库:Oracle 11g+、SQL Server、PostgreSQL等)
用UNPIVOT完成列转行,加DISTINCT过滤值重复产生的多余行,语法简洁:SELECT DISTINCT emp_name, contact FROM emp UNPIVOT ( contact FOR contact_type IN (contact1, contact2) ) AS t ORDER BY emp_name, contact; - 横向连接写法(支持
LATERAL语法的数据库:PostgreSQL、MySQL 8.0.14+等)
通过侧视图对每行员工数据做号码去重,逻辑清晰可读性强:SELECT e.emp_name, v.contact FROM emp e, LATERAL ( SELECT contact1 AS contact UNION SELECT contact2 AS contact ) v ORDER BY e.emp_name, v.contact; - 交叉枚举写法(所有支持子查询的数据库通用)
通过交叉连接构造序号枚举值,匹配对应联系方式后去重:SELECT DISTINCT e.emp_name, CASE WHEN c.seq = 1 THEN e.contact1 ELSE e.contact2 END AS contact FROM emp e CROSS JOIN (SELECT 1 AS seq UNION ALL SELECT 2 AS seq) c ORDER BY e.emp_name, contact;
内容的提问来源于stack exchange,提问作者Nikhil
相关产品推荐
相关产品推荐

