Sql server 查找';缺失';跨两个结果集的行

Sql server 查找';缺失';跨两个结果集的行,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,我已经为此挣扎了好几天,所以如果我把事情弄糊涂了,我道歉 我有一系列表,这些表定义: 技能组 技巧 上述群体中的技能(多对多) 工作角色 这些工作角色的技能(多对多) 数据库的结构如下所示: 我需要创建一个显示以下数据的结果集: 对于所有工作角色,展示这些工作中的所有技能 角色。但是,还应包括各自小组内的技能 未包含在每个角色中(用NULL或任何 其他方法) 请参阅此工作代码以创建表和数据 抱歉篇幅太长,我做了很多插入来创建一个现实的例子 请注意,PowerPoint技能不会添加到人力资源经理

我已经为此挣扎了好几天,所以如果我把事情弄糊涂了,我道歉

我有一系列表,这些表定义:

  • 技能组
  • 技巧
  • 上述群体中的技能(多对多)
  • 工作角色
  • 这些工作角色的技能(多对多)
  • 数据库的结构如下所示:

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

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

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

    请注意,
    PowerPoint
    技能不会添加到人力资源经理的
    角色中,但会添加来自同一组的其他技能。还请注意,
    招聘政策
    技能未添加到
    软件经理
    角色中,但我不需要看到此差距,因为该角色中不存在该组中的其他技能

    我希望得到的结果与此类似(为了简洁起见,不包括超级明星角色):

    roletitlegrouptitle SkillTitle SkillIsInRole
    ----------------------- -------------------------- --------------------------------------
    软件经理Microsoft Office Excel 1
    软件经理Microsoft Office Word 1
    软件经理Microsoft Office PowerPoint 1
    软件管理器Microsoft SQL Server查询设计1
    软件管理器Microsoft SQL Server存储过程1
    软件管理器Microsoft SQL Server故障转移群集1
    人力资源经理Microsoft Office Excel 1
    人力资源经理Microsoft Office Word 1
    
    人力资源经理Microsoft Office PowerPoint NULL我认为您必须准备一套所有可能的组合:一方的角色和另一方的团队技能。这是通过进行Decart乘法实现的(通常通过交叉连接实现)。因此,您将拥有一份每个角色的列表,以及一份所有可能的团队技能组合的列表。之后,您可以将此结果与表tbl_RolesSkills左连接。这会给你所需要的。您可以通过使用CTE或子查询来实现这一点

    必须看起来像

    实际上不需要交叉连接,我遗漏了“特定角色只有特定组集”的部分。只有一个子查询,也可以使用CTE(公共表表达式)完成


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

    获取与角色相关的组的所有技能有点简单,可以在下面相对自解释的
    角色中处理。从这一点上,我能想到的获取技能是否与角色“直接”相关的唯一方法是通过
    OUTER将结果集应用到角色的实际技能的结果集

    ;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
    
    编辑:
    外部应用
    可以通过
    左连接处理

    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
    

    谢谢。你能在SQL Fiddle脚本中发布一个例子吗?对不起,我在iPad上写答案,在上面写脚本对我来说很难:)太好了。非常感谢你。非常感谢你花时间理解我的例子。非常感谢。明天早上我回来工作的时候我会试试。棒极了。非常感谢。我会浏览你们的“tba”网站,当你们在找新工作时,我会检查我们的财务状况是否允许:-)请回答一个简单的问题。您的查询执行速度比Bogdan快一小部分,但代码却多得多。你知道为什么会这样吗?我选择您的答案是正确的,完全是因为这个原因。您在哪里检查了两个查询的执行时间?我并不是说我的速度更快,我认为他们必须有相似的执行时间。我检查了测试数据的SMSS客户端统计信息。你的回答慢了一点,但只差一小部分。我认为你的答案更容易阅读,我在工作中也用到了。
    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