【问题标题】:Follow-up to UNION NULLS for What-IF View ComparatorWhat-IF 视图比较器的 UNION NULLS 后续行动
【发布时间】:2018-12-19 18:03:12
【问题描述】:

这个问题是对以下问题的跟进:

purposely union'ing NULLs for a training matrix.

在之前的帖子中,我提到了一家拥有工作技能表和员工技能表的公司。在本次讨论中,我们只使用其中两名员工...

           jobskills          +             emplskills
job_code skill_desc skill_ID  |  empl_ID emplName job_code skill_ID
-------- ---------- --------  |  ------- -------- -------- --------
   APP      Cut        10     |    396     Tom       APP      10
   APP      Drill      20     |    396     Tom       APP      30
   APP      Bend       30     |    426     Bob       EXP      10
   EXP      Cut        10     |    426     Bob       EXP      20
   EXP      Drill      20     |    426     Bob       EXP      40
   EXP      Bend       30     |    426     Bob       EXP      50
   EXP      Weld       40     |
   EXP      Turn       50     |
                              +

jobskills表中,你会看到APP(学徒)职称需要3个技能——切割、钻孔、折弯(10、20、30)。同样,EXP(专家)职位需要 5 项技能(10 到 50)。

emplskills 表中,您将看到 Tom 是一名学徒 (APP),他的职位应具备所有 3 项技能,但只有 2 项。他缺少钻孔技能 (20)。以同样的方式:作为专家 (EXP) 的 Bob 应该在其职位中拥有所有 5 项技能,但缺少 Bend 技能 (30)。

在上一篇文章中,@JuanCarlosOropeza 创建了这个查询(我重新定义了一些列),它通过外部连接每个 empl_ID 的 NULL 来列出员工拥有和不具备的所有技能。

WITH required_skills as 
(
     SELECT DISTINCT 
         e.empl_ID, e.job_code, j.skill_ID, j.skill_desc
     FROM 
         emplskills e
     JOIN 
         jobskills j ON e.job_code = j.job_code
)
SELECT 
    r.empl_ID, e.emplName, r.job_code, r.skill_ID, r.skill_desc
FROM 
    required_skills r
LEFT JOIN 
    emplskills e ON r.empl_ID = e.empl_ID
                 AND r.skill_ID = e.skill_ID;

上面的查询产生了我需要将员工的技能与他自己的职位进行比较的结果:

查询结果:

empl_ID emplName job_code skill_ID skill_desc
------- -------- -------- -------- ----------
  396     Tom       APP      10       Cut
  396     Tom       APP      20       Drill
  396    {null}     APP      30       Bend
  426     Bob       EXP      10       Cut
  426     Bob       EXP      20       Drill
  426    {null}     EXP      30       Bend
  426     Bob       EXP      40       Weld
  426     Bob       EXP      50       Turn

此查询的重点是使用此查询作为源视图的培训应用程序。如果用户根据 empl_ID 进行过滤,她可以查看 Tom (396) 并发现他缺少 Bend 技能 (30)

过滤 Tom(396)

empl_ID emplName job_code skill_ID skill_desc
------- -------- -------- -------- ----------
  396     Tom       APP      10       Cut
  396     Tom       APP      20       Drill
  396    {null}     APP      30       Bend

...现在是新问题:

在培训应用程序中,我需要将员工与任何职位进行比较。因此,我需要将每个可能的工作代码组合和每个可能的技能组合都与每个员工联系起来。

我真正需要的查询的期望结果是这样的:

empl_ID emplName job_code skill_ID skill_desc
------- -------- -------- -------- ----------
  396     Tom       APP      10       Cut
  396     Tom       APP      20       Drill
  396    {null}     APP      30       Bend
  396     Tom       EXP      10       Cut
  396     Tom       EXP      20       Drill
  396    {null}     EXP      30       Bend
  396    {null}     EXP      40       Weld
  396    {null}     EXP      50       Turn
  426     Bob       APP      10       Cut
  426     Bob       APP      20       Drill
  426     Bob       APP      30       Bend
  426     Bob       EXP      10       Cut
  426     Bob       EXP      20       Drill
  426    {null}     EXP      30       Bend
  426     Bob       EXP      40       Weld
  426     Bob       EXP      50       Turn

现在,当用户过滤时,他们可以将员工与不同职位的要求进行比较。对于 Tom the apprentice,Apprentice 标题上的原始过滤仍然有效:

Filter on Tom(396) and JOB CODE (APP)
empl_ID emplName job_code skill_ID skill_desc
------- -------- -------- -------- ----------
  396     Tom       APP      10       Cut
  396     Tom       APP      20       Drill
  396    {null}     APP      30       Bend

但是,如果正在考虑将 Tom 提升为 EXPERT,经理可以立即看到 Tom 缺乏哪些专家技能:

Filter on Tom(396) and JOB CODE (EXP)
empl_ID emplName job_code skill_ID skill_desc
------- -------- -------- -------- ----------
  396     Tom       EXP      10       Cut
  396     Tom       EXP      20       Drill
  396    {null}     EXP      30       Bend
  396    {null}     EXP      40       Weld
  396    {null}     EXP      50       Turn

有没有办法改变上面的查询来完成这个?到目前为止,我对你们提供的帮助非常感谢。这是我目前工作的现实挑战。我们有大约 150 名实际工厂工人,拥有 40 多个职称。其中一些职位有超过 3 打的相关技能 ID。

最后,我尝试使用上述查询创建 VIEW AS (),但无法获得正确的语法。新查询运行后,您能帮我将其转换为 CREATE VIEW 语句吗?

再次感谢, 约翰

【问题讨论】:

  • 听起来你需要一个完整的外部联接。将查询转换为视图就像 CREATE VIEW MyView 一样简单 ....将您的查询放在这里...
  • @SeanLange 当我将上面的查询更改为 FULL OUTER JOIN 而不是 LEFT JOIN 时,我得到与上面的查询相同的 8 行结果。
  • 如上?显示了几个结果。
  • 嗨@SeanLange,在帖子顶部附近有一个WITH ... SELECT DISTINCT 声明。该语句的正下方是一个 8 行查询结果。这也是我通过 FULL OUTER JOIN 更改得到的结果
  • @SeanLange 当我用CREATE VIEW MY_VIEW AS (...) 包装上述查询时,WITH 出现语法错误,但没有解释。 ——约翰·约瑟夫

标签: sql-server null outer-join cartesian-product


【解决方案1】:

您确实应该以可消耗的格式发布数据。幸运的是,Juan Carlos Opreza 在您之前的问题中为您做到了这一点。我拿走了他并从您的其他问题中删除了“额外”数据。

CREATE TABLE emplskills 
    ([empl_ID] int, [emplName] varchar(3), [job_code] varchar(3), [skill_ID] int)
;

INSERT INTO emplskills 
    ([empl_ID], [emplName], [job_code], [skill_ID])
VALUES
    (396, 'Tom', 'APP', 10),
    (396, 'Tom', 'APP', 20),
    (426, 'Bob', 'EXP', 10),
    (426, 'Bob', 'EXP', 20),
    (426, 'Bob', 'EXP', 40),
    (426, 'Bob', 'EXP', 50)
;


CREATE TABLE jobskills 
    ([job_code] varchar(3), [skill_desc] varchar(5), [skill_ID] int)
;

INSERT INTO jobskills 
    ([job_code], [skill_desc], [skill_ID])
VALUES
    ('APP', 'Cut', 10),
    ('APP', 'Drill', 20),
    ('APP', 'Bend', 30),
    ('EXP', 'Cut', 10),
    ('EXP', 'Drill', 20),
    ('EXP', 'Bend', 30),
    ('EXP', 'Weld', 40),
    ('EXP', 'Turn', 50)
;

现在我们有了一些具体而明确的工作,让我们看看它是如何工作的。由于左连接不起作用,因为您在没有匹配时填充 empl_ID,因此您需要一些不同的方法。解决这个问题的方法不止一种。我使用交叉连接来生成所有员工和工作技能的列表。这为我们提供了您可以在左连接中使用的列表。

我不得不说你需要阅读规范化,因为这些结构相当痛苦。

select AllEmpSkills.empl_ID
    , es.emplName
    , js.job_code
    , js.skill_ID
    , js.skill_desc
from jobskills js
cross join 
(
    select distinct empl_ID from emplskills
) AllEmpSkills
left join emplskills es on es.empl_ID = AllEmpSkills.empl_ID
                    and es.skill_ID = js.skill_ID
order by AllEmpSkills.empl_ID
    , js.job_code
    , js.skill_ID

【讨论】:

  • 太棒了!我放弃了 order by 子句并对此进行了看法。完美运行。再次感谢您。
  • 最重要的是你明白它为什么起作用。不要犹豫,问你是否有你没有得到的部分。很高兴您能够使用它。
  • 好的,我看到十字架是 empl_ID 和 Skill_ID 的所有可能组合。然后左加入。我不太擅长复合选择,所以再次感谢。
  • 是的,听起来你明白了。看到这样的事情并理解它们将帮助您弄清楚如何自己变出它们。 :D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多