Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL-查询继承人以确定责任_Sql_Sql Server_Database Design_Hierarchy - Fatal编程技术网

SQL-查询继承人以确定责任

SQL-查询继承人以确定责任,sql,sql-server,database-design,hierarchy,Sql,Sql Server,Database Design,Hierarchy,假设我有一个由四个级别组成的组织层次结构: 分裂,已经 各部门 已经 团队 这在数据库中由四个表表示,记录由它们的ID链接,自动生成,每个表从1开始。例如: DEPARTMENTS departmentID departmentName divisionID 1 Finance 1 2 IT 1 3 HR 2 ... AREAS areaID

假设我有一个由四个级别组成的组织层次结构:

  • 分裂,已经
  • 各部门
  • 已经
  • 团队
这在数据库中由四个表表示,记录由它们的ID链接,自动生成,每个表从1开始。例如:

DEPARTMENTS
departmentID  departmentName  divisionID
1             Finance         1
2             IT              1
3             HR              2
...

AREAS
areaID        areaName        departmentID
1             Accounts        1
2             Payroll         1
3             Collections     1
4             Development     2
5             Tech Support    2
...
userID    role        unitID  unitType
smithj    Manager     1       Division
doej      Manager     1       Department
simpsonh  Manager     1       Area
cashj     Supervisor  1       Team
nelsonw   Supervisor  2       Team
kristofk  Supervisor  3       Team
talbots   Manager     2       Division
abbets    Manager     2       Department
lowmany   Manager     3       Department
...
等等

还存在一个UserRoles表,其中用户链接到这四个级别之一的角色。但是,此表没有显式链接到任何层次结构表。相反,每个UserRole记录由四部分组成——userID、role、unitID和unitType。例如:

DEPARTMENTS
departmentID  departmentName  divisionID
1             Finance         1
2             IT              1
3             HR              2
...

AREAS
areaID        areaName        departmentID
1             Accounts        1
2             Payroll         1
3             Collections     1
4             Development     2
5             Tech Support    2
...
userID    role        unitID  unitType
smithj    Manager     1       Division
doej      Manager     1       Department
simpsonh  Manager     1       Area
cashj     Supervisor  1       Team
nelsonw   Supervisor  2       Team
kristofk  Supervisor  3       Team
talbots   Manager     2       Division
abbets    Manager     2       Department
lowmany   Manager     3       Department
...
等等。每个ID号都可以(也将)重复多次,表示用于识别的各种不同类型的单元。要将用户/角色组合绑定到组织的特定部分,需要ID号和单位类型

业务规则是,在部门、部门或区域级别具有角色的用户被视为对其级别下的所有组织单位负责。例如,doej将负责其部门下的区域以及这些区域下的团队,但不负责其部门上的部门


在给定单元类型和ID的情况下,我如何查询此表结构以找出哪些用户对此负责?

这将是一个很长的答案,以澄清我们正在做什么

TL;DR版本

使用具有自底向上策略的递归CTE和表示角色层次结构的视图。转到最后一个代码段以获取解决方案


完整版本

您可以使用递归CTE自底向上查询分层数据—从叶到节点(这里是从区域到分区,但在您的实际示例中,只需添加团队)。此外,由于每个级别都有单独的表,我们将使用一个视图来简化它,该视图将保留整个树,并允许我们实际构建递归CTE查询。稍后再谈。让我们开始吧

准备简化数据样本

CREATE TABLE divisions ( divisionid int );
CREATE TABLE departments ( departmentid int, divisionid int);
CREATE TABLE areas ( areaid int, departmentid int);
CREATE TABLE userroles ( userid varchar(255), unitid int, unittype varchar(255));

INSERT INTO divisions VALUES (1),(2);
INSERT INTO departments VALUES (1,1),(2,2);
INSERT INTO areas VALUES (1,1),(2,1),(3,3),(4,2);
INSERT INTO userroles VALUES ('smithj',1,'Division'),('doej',1,'Department'),('simpsonh',2,'Area'),('anyother',1,'Area'),('smhg',1,'Division');
-- If you already have data in your tables and created view, proceed with this code:
DECLARE @unittype varchar(max);
DECLARE @unitid int;
SET @unittype = 'Area'; -- change it to look for what you want
SET @unitid = 2; -- change it to look for what you want

WITH cte AS (
SELECT ur.userid, r.unittype, r.unitid, r.parenttype, r.parentid
FROM roles r
LEFT JOIN userroles ur ON ur.unitid = r.unitid AND ur.unittype = r.unittype
WHERE r.unittype = @unittype AND r.unitid = @unitid
UNION ALL
SELECT ur.userid, r.unittype, r.unitid, r.parenttype, r.parentid
FROM roles r
INNER JOIN cte c ON r.unitid = c.parentid AND r.unittype = c.parenttype
INNER JOIN userroles ur ON ur.unittype = r.unittype AND ur.unitid = r.unitid
)
SELECT userid
FROM cte
WHERE userid IS NOT NULL
让我们看看
userroles
表的外观:

+----------+--------+------------+
| userid   | unitid | unittype   |
+----------+--------+------------+
| smithj   | 1      | Division   |
| doej     | 1      | Department |
| simpsonh | 2      | Area       |
| anyother | 1      | Area       |
| smhg     | 1      | Division   |
+----------+--------+------------+
现在我们实际上向前迈进了一步,开始创建视图,因为在不同的表中有不同的级别,逻辑需要使用两个
左连接,而在SQL Server中,我们不能在递归CTE查询中使用这些连接。将弹出此错误:

递归公用程序的递归部分不允许外部联接 表表达式

因此,我们正在创建roles hierarchy(角色层次结构)视图,以将左连接逻辑转换为一个表,我们可以
内部连接

CREATE VIEW roles AS (
SELECT 'Division' AS unittype, divisionid as unitid, cast(null as int) as parentid, null as parenttype FROM divisions
UNION ALL
SELECT 'Department', departmentid, divisionid, 'Division' FROM departments
UNION ALL
SELECT 'Area', areaid, departmentid, 'Department' FROM areas
);
让我们看看我们的视图
角色
呈现了什么:

+------------+--------+----------+------------+
| unittype   | unitid | parentid | parenttype |
+------------+--------+----------+------------+
| Division   | 1      | NULL     | NULL       |
| Division   | 2      | NULL     | NULL       |
| Department | 1      | 1        | Division   |
| Department | 2      | 2        | Division   |
| Area       | 1      | 1        | Department |
| Area       | 2      | 1        | Department |
| Area       | 3      | 3        | Department |
| Area       | 4      | 2        | Department |
+------------+--------+----------+------------+
到目前为止还不错。让我们为搜索条件设置两个变量并编写最终查询。我正在选择
unittype='Area'
unitid=2
。这将使预期的层次结构按如下方式运行:

(Area: 2) -> (Department: 1) -> (Division: 1)
这将为用户分配这些单元类型的责任带来结果:

simpsonh <- from Area 2
doej     <- from Department 1
smhg     <- from Division 1
smithj   <- from Division 1

在您的描述中,您谈论的是显示一个用户的责任,然后在最后,您的问题是显示谁负责层次结构中给定的单元。你到底想要哪一个?这是不明确的。@KamilG。UserRoles表包含关于个人责任的信息——我想找出哪些个人对给定的unitID/unitType组合负责。有什么我可以进一步澄清的吗?我正在准备我的答案,我认为这已经足够了。请通过编辑澄清,而不是评论。我很清楚CTE的用途。如果您觉得手动输入每个级别是更好、更灵活的解决方案,请发布您的答案。IMHO recursive CTE在未来可能会有所帮助,前提是结构可能会增长或改变,并且对其他在这个问题上遇到障碍的用户也有潜在的好处。这是任何人都希望得到的最彻底的答案——我很感谢它花了这么多时间来撰写和承诺文字。你是对的,结构可能会增长,也可能会变化,这很好地适应了这一点。“你需要一个递归的CTE来查询分层数据”到一个特定的深度——就像用户角色,如果它可以有任意的unittype值——但除此之外没有。PS@DamienH Read re&。)@philipxy我已经修改了我的答案,所以它不是说“需要”,而是说“可以使用”。