插件窝 干货文章 如何高效查询MySQL中指定部门及其所有子部门下的所有员工?

如何高效查询MySQL中指定部门及其所有子部门下的所有员工?

部门 递归 departments 字段 179    来源:    2025-03-11

要高效查询MySQL中指定部门及其所有子部门下的所有员工,通常需要处理层级结构的部门数据。假设你的部门表(departments)和员工表(employees)结构如下:

  • departments 表:

    • id:部门ID
    • name:部门名称
    • parent_id:上级部门ID(根部门的 parent_idNULL0
  • employees 表:

    • id:员工ID
    • name:员工名称
    • department_id:所属部门ID

解决方案

  1. 使用递归CTE(Common Table Expressions): MySQL 8.0及以上版本支持递归CTE,可以方便地处理层级结构数据。

    WITH RECURSIVE DepartmentTree AS (
       -- 基础查询:选择指定部门
       SELECT id, name, parent_id
       FROM departments
       WHERE id = ?  -- 替换为指定的部门ID
    
       UNION ALL
    
       -- 递归查询:选择所有子部门
       SELECT d.id, d.name, d.parent_id
       FROM departments d
       INNER JOIN DepartmentTree dt ON d.parent_id = dt.id
    )
    -- 查询所有员工
    SELECT e.*
    FROM employees e
    INNER JOIN DepartmentTree dt ON e.department_id = dt.id;
    

    解释

    • WITH RECURSIVE DepartmentTree AS (...):定义一个递归CTE,用于获取指定部门及其所有子部门。
    • 基础查询部分选择指定的部门。
    • 递归查询部分通过 INNER JOIN 连接 departments 表和 DepartmentTree,获取所有子部门。
    • 最后,通过 INNER JOIN 连接 employees 表和 DepartmentTree,获取所有员工。
  2. 使用嵌套集模型(Nested Set Model): 如果你的部门表使用了嵌套集模型(即每个部门有 leftright 字段来表示层级关系),查询会更加高效。

    SELECT e.*
    FROM employees e
    INNER JOIN departments d ON e.department_id = d.id
    WHERE d.left BETWEEN (SELECT left FROM departments WHERE id = ?)
                    AND (SELECT right FROM departments WHERE id = ?);
    

    解释

    • d.left BETWEEN ... AND ...:通过 leftright 字段来确定指定部门及其所有子部门的范围。
    • 这种方法在查询时非常高效,但需要预先维护 leftright 字段。
  3. 使用路径枚举模型(Path Enumeration Model): 如果部门表使用了路径枚举模型(即每个部门有一个 path 字段,存储从根部门到当前部门的路径),查询也可以高效进行。

    SELECT e.*
    FROM employees e
    INNER JOIN departments d ON e.department_id = d.id
    WHERE d.path LIKE CONCAT((SELECT path FROM departments WHERE id = ?), '%');
    

    解释

    • d.path LIKE ...:通过 path 字段来匹配指定部门及其所有子部门。
    • 这种方法在查询时也非常高效,但需要预先维护 path 字段。

总结

  • 递归CTE:适用于MySQL 8.0及以上版本,处理层级结构数据非常方便。
  • 嵌套集模型:查询效率高,但需要预先维护 leftright 字段。
  • 路径枚举模型:查询效率高,但需要预先维护 path 字段。

根据你的数据库设计和MySQL版本,选择最适合的方案。