2011-04-01 56 views
0

我有两个表。学生和工作。 我需要搜索拥有所有工作所需技能的学生。从两个表中查询匹配的逗号分隔值

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,',')) 

[拆分()得到逗号分隔的字符串值作为输入,并以表格的形式返回不同的值]

返回这样的结果:

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

+1

在单个列中存储像技能这样的信息的整个列表是** BAD **数据库设计。我们有什么表格和关系?我会重新设计你的设计到一张桌子学生,一张桌子的技能,以及两者之间的链接表 - 这样,你可以为任何学生分配任意数量的技能。也以同样的方式将技能表链接到您的工作。 – 2011-04-01 09:54:05

+0

1)你的表可能不在1NF,因为'MandSkills'包含非标量数据,当然SQL(服务器)不太适合查询这样的数据,所以模型对每个值使用一行; 2)您需要的关系运营商称为“关系部门”,例如google。 http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/ – onedaywhen 2011-04-01 10:03:31

+0

我感谢您的建议。我也知道这是一个糟糕的数据库设计,但是一个网站是实时的,并且存储了大量的数据。由于一些需求变化,我需要做这样的设计数据库。现在不可能重新设计数据库。谢谢。 – simplyaarti 2011-04-01 10:14:39

回答

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) 
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) 
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 
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 
    ) 

这是一个相当快的尝试,所以有可能是其他的方式来结构查询 - 值得如果你可以进行模式更改玩弄。

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操作。