多表查询需求:将员工关联部门横向展示消除重复员工记录
嘿,这个多对多关联查询导致员工记录重复的问题我太熟了!之前做人事系统时天天跟这个打交道,给你两个实用的解决思路,按需选就行:
方法一:字符串聚合(通用方案,适配部门数量不固定场景)
这种方法的核心是把同一个员工所属的所有部门名拼接成一个字符串列,让每条员工记录只出现一次,是最常用的解决方案。
首先先补全你的建表语句(包含中间关联表):
-- 员工表 CREATE TABLE `tbl_emp` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `emp_name` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT '', PRIMARY KEY (`id`) ); -- 部门表 CREATE TABLE `tbl_dept` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `dept_name` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT '', PRIMARY KEY (`id`) ); -- 员工-部门关联表(消除多对多关系) CREATE TABLE `emp_dept_rel` ( `emp_id` int(10) unsigned NOT NULL, `dept_id` int(10) unsigned NOT NULL, PRIMARY KEY (`emp_id`, `dept_id`), FOREIGN KEY (`emp_id`) REFERENCES `tbl_emp`(`id`), FOREIGN KEY (`dept_id`) REFERENCES `tbl_dept`(`id`) );
不同数据库的查询语句:
MySQL
SELECT e.id, e.emp_name, -- 用逗号分隔拼接部门名,可根据需求换分隔符 GROUP_CONCAT(d.dept_name SEPARATOR ', ') AS dept_list FROM tbl_emp e -- LEFT JOIN保证无部门的员工也能被查询到 LEFT JOIN emp_dept_rel edr ON e.id = edr.emp_id LEFT JOIN tbl_dept d ON edr.dept_id = d.id -- 按员工唯一标识分组,避免重复 GROUP BY e.id, e.emp_name;
PostgreSQL / SQL Server 2017+
这俩数据库用STRING_AGG函数,语法更简洁:
SELECT e.id, e.emp_name, STRING_AGG(d.dept_name, ', ') AS dept_list FROM tbl_emp e LEFT JOIN emp_dept_rel edr ON e.id = edr.emp_id LEFT JOIN tbl_dept d ON edr.dept_id = d.id GROUP BY e.id, e.emp_name;
小提示:MySQL的GROUP_CONCAT默认有长度限制,如果员工所属部门特别多,可以通过调整group_concat_max_len参数扩大上限。
方法二:PIVOT行转列(适合部门数量固定的场景)
如果你的公司部门数量固定且不会轻易新增(比如只有研发、运营、人事部),可以把部门转成单独的列,直观展示员工是否属于该部门。
MySQL 模拟PIVOT(MySQL无原生PIVOT,用CASE WHEN实现)
SELECT e.id, e.emp_name, MAX(CASE WHEN d.dept_name = '研发部' THEN '是' ELSE '否' END) AS 研发部, MAX(CASE WHEN d.dept_name = '运营部' THEN '是' ELSE '否' END) AS 运营部, MAX(CASE WHEN d.dept_name = '人事部' THEN '是' ELSE '否' END) AS 人事部 FROM tbl_emp e LEFT JOIN emp_dept_rel edr ON e.id = edr.emp_id LEFT JOIN tbl_dept d ON edr.dept_id = d.id GROUP BY e.id, e.emp_name;
SQL Server 原生PIVOT
SELECT id, emp_name, [研发部], [运营部], [人事部] FROM ( -- 先获取员工和对应部门的基础数据 SELECT e.id, e.emp_name, d.dept_name FROM tbl_emp e LEFT JOIN emp_dept_rel edr ON e.id = edr.emp_id LEFT JOIN tbl_dept d ON edr.dept_id = d.id ) AS src PIVOT ( -- 用COUNT统计是否属于该部门,1表示是,0表示否 COUNT(dept_name) FOR dept_name IN ([研发部], [运营部], [人事部]) ) AS pvt;
注意:这种方案的缺点是部门新增时必须修改SQL语句,适合部门架构稳定的场景。
内容的提问来源于stack exchange,提问作者Nasz Njoka Sr.
相关产品推荐
相关产品推荐

