如何用SQL将多列员工ID与姓名转为垂直输出(Unpivot实现)
解决多组EmpId/EmpName列转垂直格式的问题
嘿,我来帮你搞定这个麻烦的格式转换问题!先明确下你的场景:表里面有Cid,还有整整50组配对的EmpIdN和EmpNameN列,你不想写50次UNION ALL折腾自己,已经尝试用UNPIVOT处理ID列,现在想把对应的姓名列也一起转成目标的垂直格式。
最简洁的解决方案:用CROSS APPLY(SQL Server)或LATERAL JOIN(PostgreSQL/MySQL 8.0+)
这种方法可以一次性处理所有配对的ID和姓名列,不用重复写冗余逻辑,完美适配你有50组列的场景。
以你的示例表为例,对应的查询代码如下:
SELECT emp_label, emp_value FROM emp CROSS APPLY ( VALUES ('Emp1', CAST(EmpId1 AS VARCHAR(50))), ('EmpName1', EmpName1), ('Emp2', CAST(EmpId2 AS VARCHAR(50))), ('EmpName2', EmpName2), -- 按照这个格式继续添加,直到Emp50和EmpName50 ('Emp50', CAST(EmpId50 AS VARCHAR(50))), ('EmpName50', EmpName50) ) AS unpivoted_data(emp_label, emp_value) WHERE cid = 1;
代码逻辑解释
CROSS APPLY + VALUES组合:相当于在每行数据内部,把50组EmpIdN/EmpNameN拆分成100行(每组对应两行:ID行和姓名行),VALUES子句里的每一行就是你想要的垂直格式的一条记录。- 类型统一处理:因为
EmpId是数值类型,EmpName是字符串类型,所以需要把EmpId转成字符串(比如CAST(xxx AS VARCHAR(50))),保证输出的emp_value列类型一致,避免报错。 - 扩展性极强:你只需要照着
('EmpN', CAST(EmpIdN AS VARCHAR(50))), ('EmpNameN', EmpNameN)的格式,把50组都补进VALUES里就行,比写50次UNION ALL清爽太多。
如果坚持想用UNPIVOT怎么处理?
要是你更习惯用UNPIVOT,可以先把ID和姓名分别做unpivot,再通过标签的编号关联起来:
WITH id_unpivot AS ( SELECT REPLACE(ids, 'Emp', '') AS emp_num, CAST(id AS VARCHAR(50)) AS emp_value, 'Emp' + REPLACE(ids, 'Emp', '') AS emp_label FROM ( SELECT EmpId1 AS Emp1, EmpId2 AS Emp2, ..., EmpId50 AS Emp50 FROM emp WHERE cid = 1 ) AS upvt UNPIVOT ( id FOR ids IN (Emp1, Emp2, ..., Emp50) ) AS upvt ), name_unpivot AS ( SELECT REPLACE(names, 'EmpName', '') AS emp_num, name AS emp_value, 'EmpName' + REPLACE(names, 'EmpName', '') AS emp_label FROM ( SELECT EmpName1 AS EmpName1, EmpName2 AS EmpName2, ..., EmpName50 AS EmpName50 FROM emp WHERE cid = 1 ) AS upvt UNPIVOT ( name FOR names IN (EmpName1, EmpName2, ..., EmpName50) ) AS upvt ) SELECT emp_label, emp_value FROM id_unpivot UNION ALL SELECT emp_label, emp_value FROM name_unpivot ORDER BY emp_num;
不过这种方法需要写两次unpivot,还要处理标签的编号关联,不如CROSS APPLY直观简洁,更推荐第一种方案。
内容的提问来源于stack exchange,提问作者Jen K
相关产品推荐
相关产品推荐

