查询来自两个表的匹配逗号分隔值

时间:2011-04-01 08:50:28

标签: sql-server sql-server-2008

我有两张桌子。学生和工作。 我需要搜索具备工作所需技能的学生。

    Student                      Job
StudentId MandSkills           JobPostId    MandSkills
  208        2,16,17              36         2,16,18
  209        2,16       
  210        2,18,34        
  211        2,16,17        
  212        2,17,16,23     
  213        2,16,17        
  214        2,16,17        
  215        2,18,17,28     
  217        2,16,17

我写了一个查询

SELECT 
   S.StudentId, S.MandSkills, JP.items 
FROM 
   Split((SELECT MandSkills FROM JobPosts WHERE JobPostId = 36),',') JP, 
   Students S   
WHERE 
    JP.items IN (SELECT items FROM Split(S.MandSkills,','))

[Split()将逗号分隔的字符串值作为输入,并以表格形式返回单独的值]

返回如下结果:

studentId MandSkills items
    208 2,16,17 2
    209 2,16    2
    210 2   2
    211 2,16,17 2
    212 2,16,17 2
    213 2,16,17 2
    214 2,16,17 2
    215 2,16,17 2
    217 2,16,17 2
    218 2,16,17,26  2
    219 2,16    2
    221 2,16    2
    208 2,16,17 16
    209 2,16    16
    211 2,16,17 16
    212 2,16,17 16
    213 2,16,17 16
    214 2,16,17 16
    215 2,16,17 16
    217 2,16,17 16
    218 2,16,17,26  16
    219 2,16    16
    220 16,17   16
    221 2,16    16

它仅检查一项技能。

我想选择具备三种技能的学生。

请帮帮我。

提前致谢。

-Aarti

5 个答案:

答案 0 :(得分:0)

尝试这个(我还没有测试过):

SELECT S.StudentId, S.MandSkills, JP.items
  FROM Students S
       , Split((select MandSkills from JobPosts where JobPostId=36),',') JP
 WHERE NOT EXISTS 
         (SELECT NULL
            FROM (SELECT JP1.items JP_items, S1.items S_items
                    FROM Split((select MandSkills 
                                  from JobPosts
                                 where JobPostId=36),',') JP1
                    LEFT JOIN Split(S.MandSkills,',') S1
                    ON JP1.items = S1.items) A
          WHERE S_items IS NULL)

答案 1 :(得分:0)

你可以尝试这个..但我猜...我不知道即使有可能做这样的事情:

select * 
from Student s
join Job j on (select count(*)-sum(case when jms.items is not null then 1 else 0 end)
               from split(j.MandSkills,',') sms
               left join split(s.MandSkills,',') jms on sms.items=jms.items)=0

答案 2 :(得分:0)

Select S.StudentId, JP.MandSkills
from JobPosts JP
cross apply Split(JP.MandSkills, ',') JPS
inner join (
    select S.StudentId, S.MandSkills, SS.items
    from Students S
    cross apply Split(S.MandSkills, ',') SS) S on S.items = JPS.items
where JP.JobPostId=36
group by S.StudentId, JP.MandSkills
having LEN(JP.MandSkills)-LEN(replace(JP.MandSkills,',',''))+1 = COUNT(distinct S.items)

答案 3 :(得分:0)

我建议您更改架构,不要将技能列表存储为每个表中的CSV值。当您最终必须将值拆分并且不使用索引时,性能将受到影响。

相反,我会创建2个额外的表:

StudentSkill
-------------
StudentId
SkillId

JobSkill
--------
JobPostId
SkillId

在每种情况下,两个字段构成主键并引用每列的相应主表(即StudentId - > Student.StudentId)

现在你有一个架构可以导致SARGable(可以使用索引)的查询。

那么一个适合你的查询是:

;WITH CTEJobSkills AS
(
SELECT SkillID 
FROM JobSkill
WHERE JobPostID = 1
)

SELECT s.StudentID 
FROM Student s
WHERE NOT EXISTS
    (
        SELECT *
        FROM CTEJobSkills js
            LEFT JOIN StudentSkill ss ON js.SkillID = ss.SkillID AND ss.StudentID = s.StudentID
        WHERE ss.SkillID IS NULL
    )

这是一个相当快速的尝试,因此可能有其他方法来构建该查询 - 如果您可以更改架构值得玩弄。

答案 4 :(得分:0)

SELECT sid FROM
    (
    Select sid, jid, ssk, jsk FROM
        (SELECT id sid, regexp_split_to_table(stud.skill, ',') ssk FROM stud) s,
        (SELECT id jid, regexp_split_to_table(job.skill, ',') jsk FROM job WHERE id = 36) j
    WHERE ssk = jsk
    ORDER BY sid, jsk, ssk
    ) jn
GROUP BY sid
HAVING count(*) = (SELECT count(*) FROM (SELECT id jid, regexp_split_to_table(job.skill, ',') jsk FROM job WHERE id = 36) sj) 

抱歉,我使用POSTGRESQL进行快速检查。 regexp_split_to_table等于SQL Server中的SPLIT。 我也建议进一步规范你的表格结构。每个id->技能对使用一行可以让你摆脱SPLIT操作。