5

这几天我一直在为此苦苦挣扎,所以如果我过度混淆了事情,我深表歉意......

我有一系列表定义:

  1. 技能组
  2. 技能
  3. 上述组内的技能(多对多)
  4. 工作角色
  5. 这些工作角色的技能(多对多)

数据库的结构如下所示: 架构

我需要创建一个显示以下数据的结果集:

对于所有工作角色,显示这些工作角色中的所有技能。但是,也包括各个组中未包含在每个角色中的技能(用 NULL 或任何其他方法表示)。

请参阅此工作代码以创建表和数据。 SQL Fiddle
抱歉,我做了很多插入来创建一个现实的例子。

请注意,该PowerPoint技能并未添加到HR Manager角色中,而是添加了来自同一组的其他技能。另请注意,该Recruitment Policy技能并未添加到Software Manager角色中,但我不需要看到此差距,因为该角色中不存在该组中的其他技能。

我的目标是这样的(为简洁起见,不包括超级明星角色):

RoleTitle               GroupTitle                 SkillTitle               SkillIsInRole
----------------------- -------------------------- --------------------------------------
Software Manager        Microsoft Office           Excel                    1
Software Manager        Microsoft Office           Word                     1
Software Manager        Microsoft Office           PowerPoint               1
Software Manager        Microsoft SQL Server       Query Design             1
Software Manager        Microsoft SQL Server       Stored Procedures        1
Software Manager        Microsoft SQL Server       Failover Clustering      1
HR Manager              Microsoft Office           Excel                    1
HR Manager              Microsoft Office           Word                     1
HR Manager              Microsoft Office           PowerPoint               NULL <-- not added to role but exists in same group as other used skills
HR Manager              HR                         Recruitment Policy       1
4

2 回答 2

3

获得与角色相关的组的所有技能有点简单,在下面相对不言自明的rolescte 中处理。由此,我能想到获得技能是否与角色“直接”相关的唯一方法是OUTER APPLY将结果集与角色的实际技能结果集进行 ING。

;WITH skills AS
(
  SELECT g.GroupId, g.GroupTitle, s.SkillId, s.SkillTitle
  FROM @tbl_GroupsSkills gs
  INNER JOIN @tbl_Groups g ON g.GroupId = gs.GroupId
  INNER JOIN @tbl_Skills s ON s.SkillId = gs.SkillId
)
, roles AS
(
  SELECT DISTINCT jr.Id RoleId, jr.RoleTitle, gs.GroupId
  FROM @tbl_jobroles jr
  INNER JOIN @tbl_rolesskills rs ON rs.RoleId = jr.ID
  INNER JOIN @tbl_GroupsSkills gs ON gs.LinkId = rs.LinkId
)
SELECT 
    roles.RoleTitle, 
    skills.GroupTitle, 
    skills.SkillTitle,
    t.SkillIsInRole
FROM skills
JOIN roles ON roles.GroupId = skills.GroupId
OUTER APPLY
(
  SELECT 1 SkillIsInRole
  FROM @tbl_rolesskills rs 
  INNER JOIN @tbl_jobroles r ON rs.RoleID = r.ID 
  INNER JOIN @tbl_groupsskills gs ON gs.LinkID = rs.LinkID 
  INNER JOIN @tbl_groups g ON g.groupID = gs.GroupID 
  INNER JOIN @tbl_skills s ON s.skillID = gs.SkillID
  WHERE s.SkillId = skills.SkillId
  AND g.GroupId = skills.GroupId
  AND r.Id = roles.RoleId
) t
ORDER BY roles.RoleTitle, skills.GroupTitle, skills.SkillTitle

编辑:OUTER APPLY可以用LEFT JOIN

LEFT JOIN (
  SELECT s.SkillId, g.GroupId, r.Id RoleId, 1 SkillIsInRole
  FROM @tbl_rolesskills rs 
  INNER JOIN @tbl_jobroles r ON rs.RoleID = r.ID 
  INNER JOIN @tbl_groupsskills gs ON gs.LinkID = rs.LinkID 
  INNER JOIN @tbl_groups g ON g.groupID = gs.GroupID 
  INNER JOIN @tbl_skills s ON s.skillID = gs.SkillID
) t ON t.SkillId = skills.SkillId
   AND t.GroupId = skills.GroupId
   AND t.RoleId = roles.RoleId

演示

于 2013-11-10T19:11:32.690 回答
1

我认为您必须从一侧准备一组所有可能的组合角色,从另一侧准备组技能。这是通过进行 Decart 乘法(通常由 CROSS JOIN 完成)来完成的。因此,您将获得每个角色的列表以及所有可能的组技能组合列表。之后,您可以使用表 tbl_RolesSkills LEFT JOIN 这个结果。这会给你所需要的。您可以使用 CTE 或子查询来执行此操作。

必须看起来像这个例子

实际上不需要 CROSS JOIN,我错过了“特定角色只有一个特定的组集”的部分。只有一个子查询,也可以用 CTE(公用表表达式)来完成。

我也排除了“超级明星”的角色。如果要添加它,只需删除 WHERE 部分。

于 2013-11-10T18:26:45.503 回答