使用sql查询部门表中某一个部门的下级部门,部门表是树结构有pid;

背景:

在工作中经常需要使用到树结构,一般情况是将数据查到内存中,整理数据结构后使用后端代码进行组装树,现在如果让你用sql代码来进行查找某一个部门下的子部门有哪些,你又该如何应对呢.

今天分享关于这个问题的思考

表结构:

CREATE TABLE `xc_department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pid` int(11) NOT NULL DEFAULT '0' COMMENT '父节点ID  0代表公司',
  `department_name` varchar(255) DEFAULT NULL COMMENT '部门名称',
  `path` varchar(255) DEFAULT NULL COMMENT '路径',
  `direct_leader_uid` int(11) DEFAULT NULL COMMENT '直属领导uid',
  `direct_leader_name` varchar(24) DEFAULT NULL COMMENT '直属领导名字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 COMMENT='部门组织表';

需求:给出一个部门的id,查找这个部门(包括这个部门)的所有下级部门的id.例如某个部门id为2,下级部门有3,4,5,6,7,则查找结果应该是:2,3,4,5,6,7.这个需求的作用是统计该部门下的所有的用户数量.

写法1:

SELECT
    t3.id
        FROM
            (
                SELECT
                    t1.*,
                    IF
                        (
                                find_in_set( t1.pid, @pids ) > 0,
                                @pids := concat( @pids, ',', t1.id ),
                                0
                        ) AS ischild
                FROM
                        ( SELECT * FROM xc_department ) t1,
                        ( SELECT @pids := 2) t2
            ) t3
        WHERE
            ischild != 0
	OR t3.id = 2;
	

解读:

这段 SQL 查询中的 IF 语句用于在查询结果中创建一个名为 ischild 的列,其值取决于条件的成立与否。让我来解释其中的部分:

  1. `IF(condition, value_if_true, value_if_false)`: 这是 MySQL 中的条件语句,它根据 condition 的真假返回不同的值。在这个查询中,condition 是 `find_in_set( t1.pid, @pids ) > 0`,value_if_true 是 `@pids := concat( @pids, ',', t1.id )`,而 value_if_false 是 0。

  2. `find_in_set( t1.pid, @pids )`: 这是 MySQL 中的函数,用于在逗号分隔的字符串中查找某个值。在这里,它的作用是检查变量 @pids 中是否包含 t1.pid 的值。

  3. `@pids := concat( @pids, ',', t1.id )`: 这部分是赋值操作,它的作用是将 t1.id 的值追加到变量 @pids 的末尾,以逗号分隔不同的部门ID。

  4. `0`: 这是在条件不成立时要返回的值。

因此,整个 IF 语句的作用是:如果 t1.pid 的值在变量 @pids 中存在,就将 t1.id 的值追加到 @pids 的末尾;否则返回 0。这个逻辑似乎是在处理部门之间的父子关系路径,以便在查询结果中标识出哪些部门是子部门。

写法2:

	SELECT  
    t1.id  
FROM  
    xc_department t1  
JOIN  
    (SELECT @pids := 2) t2  
JOIN  
    (SELECT   
        t1.*,  
        IF(  
            find_in_set(t1.pid, @pids) > 0,  
            @pids := concat(@pids, ',', t1.id),  
            0  
        ) AS ischild  
    FROM   
        xc_department t1  
    ) t3 ON t3.id = t1.id  
WHERE  
    ischild != 0 OR t1.id = 2;  

解读;

这个 SQL 查询的目的是从名为 `xc_department` 的表中选择部门的 ID,并标识出哪些部门是子部门。以下是对这个查询的解读:

  1. 初始化变量:首先,它初始化了一个用户变量 @pids,并将其设为 2。

  2. 创建临时表:它创建了一个临时表 t3,其中包含了 xc_department 表中的所有列,并增加了一个名为 ischild 的列。ischild 列的值取决于是否满足了条件。如果 t1.pid 的值在变量 @pids 中存在,则将 t1.id 的值追加到 @pids 的末尾;否则返回 0。

  3. 连接表:使用了JOIN语法将 t1 表与 t3 表连接,条件是 t3.id = t1.id。这确保了只有那些具有子部门或者id等于2的部门被选择出来。

  4. 选择结果:最终查询选择了 t1 表中的 id 列,同时过滤出 ischild 不等于 0 的行,以及 id 等于 2 的行。

总体来说,这个查询的目的是选择部门的 ID,并且标识出哪些部门是子部门,以便在查询结果中进行进一步的处理或展示。

最后从查询结果也能看到两者的查询结果是一致的,也就是两个sql是等价的,有任何疑问可以评论区讨论或者私信我

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以用以下SQL语句:SELECT department, COUNT(*) AS total FROM employees INNER JOIN departments ON employees.department_id = departments.department_id GROUP BY department; ### 回答2: 在SQL Server 2008中,要查询部门及子部门的人数,需要使用递归查询的方法。假设有两个表格,一个部门表(department),包含部门编号(dept_id)和部门名称(dept_name);另一个是员工表(employee),包含员工编号(emp_id)、员工姓名(emp_name)和所属部门编号(dept_id)。 首先,我们需要创建一个递归查询的公用表表达式(CTE)。在CTE中,我们定义一个递归部分,用于查询直属子部门的人数,并将其作为结果集的一部分返回。然后,我们使用递归部分来连接自身,查询下一级子部门的人数,直到所有子部门都被覆盖。 下面是递归查询的SQL语句: WITH RecursiveCTE AS ( SELECT dept_id, dept_name, 0 AS level FROM department WHERE dept_id = '顶层部门编号' -- 指定顶层部门编号 UNION ALL SELECT d.dept_id, d.dept_name, r.level + 1 FROM department d INNER JOIN RecursiveCTE r ON d.parent_dept_id = r.dept_id ) SELECT dept_id, dept_name, COUNT(e.emp_id) AS total_employees FROM RecursiveCTE r LEFT JOIN employee e ON r.dept_id = e.dept_id GROUP BY dept_id, dept_name; 以上SQL语句中,我们首先指定了顶层部门编号,然后使用了UNION操作符将其与递归部分连接起来。在递归部分中,我们连接了部门表自身,并使用INNER JOIN关键字将递归查询的结果与部门表进行连接。最后,我们使用LEFT JOIN关键字将递归查询的结果与员工表进行连接,并使用COUNT函数计算每个部门及其子部门的人数。 执行以上SQL语句后,将会返回包含部门编号(dept_id)、部门名称(dept_name)和人数(total_employees)的结果集,其中人数表示该部门及其子部门的所有员工的数量。 需要特别注意的是,以上SQL语句假设部门表中包含一个字段(parent_dept_id)用于表示部门的上级部门。如果部门表结构有所不同,请相应修改SQL语句中的字段名。 ### 回答3: 要查询部门及子部门人数,可以使用递归查询来实现。 首先,假设我们有两个表:部门表(Department)和员工表(Employee),它们的结构如下: 部门表(Department): - 部门ID(DepartmentID) - 部门名称(DepartmentName) - 上级部门ID(ParentDepartmentID) 员工表(Employee): - 员工ID(EmployeeID) - 员工姓名(EmployeeName) - 所属部门ID(DepartmentID) 现在,我们需要查询每个部门及其子部门的人数。下面是一种实现方式: 1. 首先,我们以部门表为基准,使用递归查询来获取每个部门的子部门ID,可以编写如下SQL语句: ```sql WITH CTE AS ( SELECT DepartmentID, ParentDepartmentID FROM Department WHERE DepartmentID = @DepartmentID -- 设定初始部门ID UNION ALL SELECT D.DepartmentID, D.ParentDepartmentID FROM Department D INNER JOIN CTE C ON C.DepartmentID = D.ParentDepartmentID ) SELECT DepartmentID FROM CTE ``` 2. 接下来,我们可以将上面的查询结果作为子查询,并使用COUNT函数来统计每个部门及其子部门的人数。完整的查询语句如下: ```sql WITH CTE AS ( SELECT DepartmentID, ParentDepartmentID FROM Department WHERE DepartmentID = @DepartmentID -- 设定初始部门ID UNION ALL SELECT D.DepartmentID, D.ParentDepartmentID FROM Department D INNER JOIN CTE C ON C.DepartmentID = D.ParentDepartmentID ) SELECT D.DepartmentID, D.DepartmentName, COUNT(E.EmployeeID) AS EmployeeCount FROM CTE C INNER JOIN Department D ON C.DepartmentID = D.DepartmentID LEFT JOIN Employee E ON D.DepartmentID = E.DepartmentID GROUP BY D.DepartmentID, D.DepartmentName ``` 以上查询将返回部门ID(DepartmentID),部门名称(DepartmentName)以及每个部门及其子部门的人数(EmployeeCount)。 注意:在实际使用中,请根据实际情况修改表名、字段名以及设定初始部门ID的方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值