查找子部门中的员工-PHP
我正在使用Codeigniter+MySQL+Active Record构建一个具有组织结构图的项目 有列为组织树的部门、用于人员信息的员工、员工角色和我存储匹配的员工部门: 部门-员工-角色 您可以看到以下结构: 部门(父id用于构建树) 员工(原始员工信息) 员工角色(权重最低,层级最高) 员工部门(在哪个部门-谁-什么角色) 在以后的阶段中,一名员工可能属于两个或多个具有不同角色的部门。这就是为什么我对多对多部门使用单独的表格。在这种情况下,让我们保持简单,并假设1名员工属于1个部门 我想做什么:查找子部门中的员工-PHP,php,mysql,codeigniter,recursion,activerecord,Php,Mysql,Codeigniter,Recursion,Activerecord,我正在使用Codeigniter+MySQL+Active Record构建一个具有组织结构图的项目 有列为组织树的部门、用于人员信息的员工、员工角色和我存储匹配的员工部门: 部门-员工-角色 您可以看到以下结构: 部门(父id用于构建树) 员工(原始员工信息) 员工角色(权重最低,层级最高) 员工部门(在哪个部门-谁-什么角色) 在以后的阶段中,一名员工可能属于两个或多个具有不同角色的部门。这就是为什么我对多对多部门使用单独的表格。在这种情况下,让我们保持简单,并假设1名员工属于1个部
你知道如何做到这一点吗 是的,要完成它,必须使用递归过程。(我正在使用MySQL 5.6.19) 我在存储过程之前创建了一些测试数据:
create table departments
(
id int not null primary key auto_increment,
parent_id int,
department_name varchar(100)
);
insert into departments (id,parent_id,department_name)
values
(1,0,'Test A'),
(2,1,'Test B'),
(3,2,'Test C');
create table staff
(
id int not null primary key auto_increment,
ip_address varchar(100),
username varchar(100)
);
insert into staff values
(1,'127.0.0.1','ats'),
(2,'127.0.0.1','admin'),
(3,'127.0.0.1','george'),
(4,'127.0.0.1','jhon')
;
create table staff_roles
(
role_id int not null primary key auto_increment,
role_name varchar(100),
role_height int
);
insert into staff_roles values
(1,'Manager',0),
(2,'Supervisor',1),
(3,'Employee',2)
;
create table staff_departments
(
staff_department_id int not null primary key auto_increment,
department_id int,
staff_id int,
role_id int
);
insert into staff_departments values
(1,1,2,1),
(2,2,1,2),
(3,3,3,3),
(4,3,4,3);
是接收find_related_staff
参数的过程,根据该值将在staff_id
表中查找staff_departments
变量角色id
将最终结果累加为逗号分隔的值@result
是在子部门中搜索并将员工id放入find_recursive
变量的过程@result
delimiter $$
drop procedure if exists find_related_staff$$
create procedure find_related_staff(p_id int)
begin
declare p_role_id int;
declare p_department_id int;
declare p_return varchar(255) default '';
declare p_role varchar(100);
select d.role_id, d.department_id, r.role_name
into p_role_id,p_department_id, p_role
from staff_departments d
inner join staff_roles r on d.role_id = r.role_id
where d.staff_id = p_id
limit 1;
case p_role_id
when 3 then -- employee (return the same id)
set @result = p_id;
when 2 then -- supervisor
select group_concat(s.staff_id)
into @result
from staff_departments s
where
s.role_id = 3
and s.department_id in
( select d.id
from departments d
where d.parent_id = p_department_id )
and s.role_id <> p_id;
when 1 then -- manager (complex recursive query)
select coalesce(group_concat(s.staff_id),'')
into @result
from staff_departments s
where
s.department_id = p_department_id
and s.staff_id <> p_id;
-- here we go!
call find_recursive(p_department_id);
end case;
select @result as result, p_role as role;
end $$
delimiter ;
delimiter $$
drop procedure if exists find_recursive$$
create procedure find_recursive(p_dept_id int)
begin
declare done int default false;
declare p_department int default false;
declare tmp_result varchar(255) default '';
-- cursor for all depend departments
declare c_departments cursor for
select s.department_id
from staff_departments s
where
s.department_id in
( select d.id
from departments d
where d.parent_id = p_dept_id );
declare continue handler for not found set done = true;
-- getting current departmens
set tmp_result =
(select coalesce(group_concat(s.staff_id),'')
from staff_departments s
where
s.department_id in
( select d.id
from departments d
where d.parent_id = p_dept_id ));
if length(tmp_result) > 0 then
if length(@result) > 0 then
set @result = concat(@result,',',tmp_result);
else
set @result = tmp_result;
end if;
open c_departments;
read_loop: loop
fetch c_departments into p_department;
if done then
leave read_loop;
end if;
call find_recursive(p_department);
end loop;
close c_departments;
end if;
end $$
delimiter ;
现在,我们在您的staff\u departments
表上有以下配置:
+---------------------+---------------+----------+---------+
| staff_department_id | department_id | staff_id | role_id |
+---------------------+---------------+----------+---------+
| 1 | 1 | 2 | 1 |
| 2 | 2 | 1 | 2 |
| 3 | 3 | 3 | 3 |
| 4 | 3 | 4 | 3 |
+---------------------+---------------+----------+---------+
运行每个案例:
call find_related_staff(2);
+--------+---------+
| result | role |
+--------+---------+
| 1,3,4 | Manager |
+--------+---------+
call find_related_staff(1);
+--------+------------+
| result | role |
+--------+------------+
| 3,4 | Supervisor |
+--------+------------+
call find_related_staff(3);
+--------+----------+
| result | role |
+--------+----------+
| 3 | Employee |
+--------+----------+
call find_related_staff(4);
+--------+----------+
| result | role |
+--------+----------+
| 4 | Employee |
+--------+----------+
好的,我认为,为了让事情更容易理解,我们需要把你的问题分解成小块(我只关注你说你真的需要帮助的部分:经理的递归) 首先,我们获得与用户关联的当前部门的身份验证。正如您所说,您只有当前签名的员工的ID,因此我们将从该ID开始。假设用户id被分配给变量$user\u id
$user_department = $this->db->get_where('staff_departments', ['staff_id' => $user_id])->row();
现在我们有了这个部门,我们检查一下用户在这个部门中的角色是什么。我们将把该信息添加到$user\u department对象:
$user_department->role = $this->db->get_where('staff_roles', ['role_id' => $user_department->role_id])->row();
让我们检查一下用户角色的权重,好吗?如果为0,我们知道它是该部门的经理,因此我们将递归查找嵌套的部门及其员工信息。根据您的逻辑,我们可以在此处检查用户是否是主管,并在必要时上报。像这样:
if ($user_department->role->role_weight <= 1) {
// the user is a supervisor OR a manager, but both those can see, at least, the current department's staff information
$user_department->staff = $this->db->get_where('staff_departments', ['department_id' => $user_department->department_id]);
// now is the user a manager? If so, let's find nested departments
if ($user_department->role->role_weight === 0) {
$user_department->childs = $this->getChildDepartmentsAndStaffOf($user_department->department_id);
}
}
现在,你有了你想要的结构。我知道这可能会被重构,但我认为这足以让你得到答案,并为你指明正确的道路
希望我能帮点忙。我认为关系数据库中分层数据最强大的模式是 给定
部门
表的示例数据:
+---------------------+---------------+----------+---------+
| staff_department_id | department_id | staff_id | role_id |
+---------------------+---------------+----------+---------+
| 1 | 1 | 2 | 1 |
| 2 | 2 | 1 | 2 |
| 3 | 3 | 3 | 3 |
| 4 | 3 | 4 | 3 |
+---------------------+---------------+----------+---------+
department_id | parent_id | department_name
--------------|-----------|----------------
1 | 0 |测试A
2 | 1 |测试B
3 | 2 |测试C
您的闭包表(我们称之为departments\u tree
)如下所示:
super_id | sub_id
---------|-------
1 | 1
1 | 2
1 | 3
2 | 2
2 | 3
3 | 3
读作:super\u id
=上级部门id<代码>子部门id=下属部门id
假设登录用户是部门id为2的部门经理,则获取所有“受监督”员工的查询为:
选择不同的s*
来自部门
在sd.department\u id=t.sub\u id上加入stuff\u departments sd
在s.id=sd.staff\u id上加入员工
其中t.super_id=2
可以使用触发器填充和更新闭包表
插入触发器:
分隔符//
为每行的“departments”在“departments”上插入后创建触发器“departments”
插入到部门树(超级id、子id)
选择new.department\u id、new.department\u id
联合所有
选择super\u id、new.department\u id
从树上
其中sub_id=new.parent_id;
结束//
定界符;
删除触发器:
分隔符//
在删除之前创建触发器'departments\u\u delete''
public function getChildDepartmentsAndStaffOf($department_id)
{
$child_departments = $this->db->get_where('departments', ['parent_id' => $department_id]);
if (! $child_departments) {
return null;
}
foreach ($child_departments as &$department) {
$department->staff = $this->db->get_where('staff_departments', ['department_id' => $department->department_id]);
$department->childs = $this->getChildDepartmentsAndStaffOf($department->department_id);
}
return $child_departments;
}
class DB {
private $servername = "127.0.0.1";
private $username = "root";
private $password = "root";
private $dbname = "test";
private $port = '3306';
public function getRecursiveDepts($deptIds) {
if (!is_array($deptIds)) {
$deptIds = array($deptIds);
}
$sql = "SELECT id FROM Departments WHERE parentId IN (";
$sql .= implode(', ', $deptIds);
$sql .= ")";
$conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname, $this->port);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$newDept = array();
while($row = $result->fetch_assoc()) {
array_push($newDept, $row['id']);
}
$conn->close();
$moreDepts = $this->getRecursiveDepts($newDept);
if (is_null($moreDepts)) {
$finalIds = array_unique(array_merge($deptIds, $newDept));
} else {
$finalIds = array_unique(array_merge($deptIds, $newDept, $moreDepts));
}
return $finalIds;
} else {
$conn->close();
return null;
}
}
public function getRoles($empId) {
$sql = "SELECT role_id, department_id FROM staff_departmen_role WHERE staff_id = '$empId' GROUP BY role_id, department_id";
$conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname, $this->port);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$emp = array();
while($row = $result->fetch_assoc()) {
if (!array_key_exists($row['role_id'], $emp)) {
$emp[$row['role_id']] = array();
}
array_push($emp[$row['role_id']], $row['department_id']);
}
}
$conn->close();
return $emp;
}
public function getEmpDetails($empId) {
$sql = "SELECT role_id, department_id FROM staff_departmen_role WHERE staff_id = '$empId' GROUP BY role_id, department_id";
$conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname, $this->port);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$emp = array();
while($row = $result->fetch_assoc()) {
if (!array_key_exists($row['role_id'], $emp)) {
$emp[$row['role_id']] = array();
}
array_push($emp[$row['role_id']], $row['department_id']);
}
}
$conn->close();
return $emp;
}
}
<?php
include_once 'db.php';
$objDB = new DB();
$empId = 2;
$emps = $objDB->getRoles($empId);
foreach ($emps as $roleId => $deptIds) {
switch ($roleId) {
case 1:
$allDeptIds = $objDB->getRecursiveDepts($deptIds);
break;
case 2://Supervisor GetEmpIds of current dept role >= 2
break;
case 3://Employee GetEmpIds of current dept role >= 2
$emp = $objDB->getEmpDetails($empId);
break;
default:
# code...
break;
}
}
$data = $objDB->getRecursiveDepts($empId);
print_r($data);
?>