如何将同一张表中的列转置为行?
解决方案:SQL列转行(Unpivoting)实现
这是典型的**列转行(Unpivoting)**需求,目的是把原表中多个同类型的列(Dept1/Dept2/Dept3)转换成多行记录。下面提供几种适配不同数据库的实现方式:
1. 通用方案:使用UNION ALL(支持所有SQL数据库)
这种方法兼容性最强,几乎所有数据库都支持,逻辑也直白易懂:
SELECT EmployeeId, Dept1 AS Dept FROM Employee_History WHERE Dept1 IS NOT NULL -- 可选:过滤空值,不需要可以删除该行 UNION ALL SELECT EmployeeId, Dept2 AS Dept FROM Employee_History WHERE Dept2 IS NOT NULL UNION ALL SELECT EmployeeId, Dept3 AS Dept FROM Employee_History WHERE Dept3 IS NOT NULL;
说明:
- 使用
UNION ALL而非UNION:前者不会自动去重,性能更高,符合我们保留所有有效部门记录的需求;如果你的场景需要去重,可以替换为UNION。 WHERE子句是可选的,如果允许部门值为空,可以直接去掉。
2. 专用语法:UNPIVOT(适用于SQL Server、Oracle等支持该语法的数据库)
如果你的数据库支持原生UNPIVOT语法,用这种方式更简洁:
SELECT EmployeeId, Dept FROM Employee_History UNPIVOT ( Dept FOR DeptColumns IN (Dept1, Dept2, Dept3) ) AS UnpivotResult;
说明:
Dept是转置后生成的新列名,对应原表中的部门值;DeptColumns是临时生成的列(我们不需要它,所以查询时没选),用来存储原表的列名(比如Dept1/Dept2/Dept3);- 该语法会自动过滤空值,不需要额外写
WHERE条件。
3. MySQL 专属方案(无原生UNPIVOT时)
MySQL没有原生的UNPIVOT,除了用上面的UNION ALL,还可以用CROSS JOIN结合CASE的方式实现:
SELECT eh.EmployeeId, CASE num.dept_idx WHEN 1 THEN eh.Dept1 WHEN 2 THEN eh.Dept2 WHEN 3 THEN eh.Dept3 END AS Dept FROM Employee_History eh CROSS JOIN ( SELECT 1 AS dept_idx UNION ALL SELECT 2 UNION ALL SELECT 3 ) num WHERE CASE num.dept_idx WHEN 1 THEN eh.Dept1 WHEN 2 THEN eh.Dept2 WHEN 3 THEN eh.Dept3 END IS NOT NULL;
说明:
- 这里通过
CROSS JOIN生成3行临时记录,配合CASE语句把原表的列值依次取出来,最终实现列转行; - 同样,
WHERE子句用来过滤空值,不需要可以删除。
针对你的测试数据,以上三种方法都能得到你预期的输出结果:
EmployeeId Dept 150 10 150 55 150 6
内容的提问来源于stack exchange,提问作者Martin James
相关产品推荐
相关产品推荐

