【问题标题】:SQL server matching two table on a columnSQL server 匹配列上的两个表
【发布时间】:2017-07-23 16:02:54
【问题描述】:

我有两个表,一个存储用户技能,另一个存储工作所需的技能。我想匹配每个用户与工作匹配的技能。 表结构为

Table1: User_Skills
| ID | User_ID | Skill    |
---------------------------
| 1  |  1      |  .Net    |
---------------------------
| 2  |  1      |  Software|
---------------------------
| 3  |  1      |  Engineer|
---------------------------
| 4  |  2      |  .Net    |
---------------------------
| 5  |  2      |  Software|
---------------------------

Table2: Job_Skills_Requirement
| ID | Job_ID | Skill     |
--------------------------
| 1  |  1      |  .Net    |
---------------------------
| 2  |  1      |  Engineer|
---------------------------
| 3  |  1      |  HTML    |
---------------------------
| 4  |  2      |  Software|
---------------------------
| 5  |  2      |  HTML    |
---------------------------

我试图用逗号分隔技能并进行比较,但它们的顺序可能不同。

编辑 这里的所有答案都很棒。我正在寻找的结果是将所有作业与所有用户匹配,稍后我还将匹配其他属性。

【问题讨论】:

  • 请记得展示您已经尝试过的内容。
  • 请编辑问题并显示您想要的结果。

标签: sql sql-server select join


【解决方案1】:

您可以通过skill 列加入表格并计算匹配项:

SELECT   user_id, job_id, COUNT(*) AS matching_skills
FROM     user_skills u
JOIN     job_skills_requirement j ON u.skill = j.skill
GROUP BY user_id, job_id

编辑:
如果您还想显示没有匹配技能的用户和工作,则可以改用full outer join

SELECT          user_id, job_id, COUNT(*) AS matching_skills
FROM            user_skills u
FULL OUTER JOIN job_skills_requirement j ON u.skill = j.skill
GROUP BY        user_id, job_id

编辑 2:
正如 Jiri Tousek 评论的那样,上面的查询将产生nulls,其中用户和工作之间没有匹配。如果您想要它们之间的完整笛卡尔积,您可以使用(滥用?)cross join 语法并计算每个用户和每个工作之间实际匹配的技能数量:

SELECT     user_id, 
           job_id,
           COUNT(CASE WHEN u.skill = j.skill THEN 1 END) AS matching_skills
FROM       user_skills u
CROSS JOIN job_skills_requirement j
GROUP BY   user_id, job_id

【讨论】:

  • 这对于没有共同技能的组合如何工作?
  • @JiriTousek 因为JOIN,它会排除它们。如果要包含不匹配项,则需要将其设为 LEFT JOIN 而不是 JOINLEFT JOIN 包括连接左侧表中与连接右侧表中的任何行都不匹配的行。对于没有匹配的行,右侧表中的列将为空。
  • @JiriTousek 与当前查询,没有匹配的用户和作业将被忽略。如果您也想显示它们,您可以使用完整的外部联接而不是内部联接 - 有关详细信息,请参阅我编辑的答案。
  • 我认为完全外连接会产生像null, SQL developer, 1John, null, 1 这样的行,而不是John, SQL Developer, 0。 Oracle 上的测试似乎支持这一点。不确定 OP 是否需要这些,我只是想知道如何才能对完全不匹配进行正确处理。
  • @JiriTousek 说得好,谢谢!使用(滥用?)cross join 似乎可以解决问题(有关详细信息,请参阅我编辑的答案)。
【解决方案2】:

如果您想匹配所有个用户和所有个工作,那么 Mureinik 的其他出色答案是不正确的。

您需要先生成所有行,我会使用 cross join 来完成,然后计算匹配的行:

select u.user_id, j.job_id, count(jsr.job_id) as skills_in_common
from users u cross join
     jobs j left join
     user_skills us
     on us.user_id = u.user_id left join
     Job_Skills_Requirement jsr
     on jsr.job_id = j.job_id and
        jsr.skill = us.skill
group by u.user_id, j.job_id;

注意:这假定存在 usersjobs 表。您当然可以使用子查询来生成这些。

【讨论】:

    【解决方案3】:
    WITH User_Skills(ID,User_ID,Skill)AS(
       SELECT 1,1,'.Net' UNION ALL
       SELECT 2,1,'Software' UNION ALL
       SELECT 3,1,'Engineer' UNION ALL
       SELECT 4,2,'.Net' UNION ALL
       SELECT 5,2 ,'Software'
    ),Job_Skills_Requirement(ID,Job_ID,Skill)AS(
       SELECT 1,1,'.Net' UNION ALL
       SELECT 2,1,'Engineer' UNION ALL
       SELECT 3,1,'HTML' UNION ALL
       SELECT 4,2,'Software' UNION ALL
       SELECT 5,2 ,'HTML'
    ),Job_User_Skill AS (
       SELECT j.Job_ID,u.User_ID,u.Skill
       FROM Job_Skills_Requirement AS j INNER JOIN User_Skills AS u ON u.Skill=j.Skill
    )
    SELECT jus.Job_ID,jus.User_ID,COUNT(jus.Skill),STUFF(c.Skills,1,1,'') AS Skill
    FROM Job_User_Skill AS jus
    CROSS APPLY(SELECT ','+j.Skill FROM Job_User_Skill AS j WHERE j.Job_ID=jus.Job_ID AND j.User_ID=jus.User_ID FOR XML PATH('')) c(Skills)
    GROUP BY jus.Job_ID,jus.User_ID,c.Skills
    ORDER BY jus.Job_ID
    
    Job_ID User_ID 技能 ----------- ------------ ----------- ------------- 1 1 2 .Net,工程师 1 2 1 .Net 2 1 1 软件 2 2 1 软件

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-31
      • 1970-01-01
      • 2014-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-16
      相关资源
      最近更新 更多