在两个结果集中查找"缺失"行

Evi*_*lDr 5 t-sql sql-server sql-server-2012

几天来我一直在苦苦挣扎,如果我过度混淆了事情,那么道歉......

我有一系列表定义:

  1. 各种技能
  2. 技能
  3. 上述群体中的技能(多对多)
  4. 工作角色
  5. 这些工作角色的技能(多对多)

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

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

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

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

请注意,该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
Run Code Online (Sandbox Code Playgroud)

T I*_*T I 3

获取与角色相关的团队的所有技能有些简单,并在roles下面相对不言自明的 cte 中处理。由此,我能想到获得技能是否与角色“直接”相关的唯一方法是将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
Run Code Online (Sandbox Code Playgroud)

编辑: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
Run Code Online (Sandbox Code Playgroud)

演示