我有桌子:
Candidates
CandidateLanguages
CandidateSkills
每位候选人可能拥有1种以上的语言和1种以上的技能
因此对于Candidate
“FRED”,他在CandidateLanguages
中的记录可能是
FRED - ENGLISH
FRED - FRENCH
他在CandidateSkills
的记录可能是
FRED - RUNNING
FRED - JUMPING
和Candidate
“JIM”他在CandidateLanguages
的记录可能是
JIM - ENGLISH
他在CandidateSkills
的记录可能是
JIM - RUNNING
我的查询需要选择符合多种技能和语言的候选人。
例如英文:
选择所有选定语言的所有候选人,并拥有所有选定的技能......
或换句话说......
SELECT ALL candidates WHERE
(language = 'FRENCH' AND language is 'ENGLISH') AND
(skill = 'RUNNING' AND skill = 'JUMPING')
在上述两位候选人中,这应该只返回“FRED”
我理解问题是尝试从语言和技能表中选择多个记录,我认为可能需要连接,但现在我迷路了...
答案 0 :(得分:4)
您正在解决的问题称为关系部门。
请参阅此文: Divided We Stand: The SQL of Relational Division 以及以下几个方法来解决问题: How to filter SQL results in a has-many-through relation
解决问题的一种方法(一般来说 - 效率最高):
SELECT ALL c.candidate
FROM Candidates c
JOIN CandidateLanguages lang1
ON lang1.candidate = c.candidate
AND lang1.language = 'English'
JOIN CandidateLanguages lang2
ON lang2.candidate = c.candidate
AND lang2.language = 'French'
JOIN CandidateSkills sk1
ON sk1.candidate = candidate
AND sk1.skill = 'Running'
JOIN CandidateSkills sk2
ON sk2.candidate = candidate
AND sk2.skill = 'Jumping' ;
另一种似乎更容易编写的方法,特别是如果涉及很多语言和技能,则在每个方法中使用两个派生表GROUP BY
:
SELECT ALL c.candidate
FROM Candidates c
JOIN
( SELECT candidate
FROM CandidateLanguages
WHERE language IN ('English', 'French')
GROUP BY candidate
HAVING COUNT(*) = 2 -- the number of languages
) AS lang
ON lang.candidate = c.candidate
JOIN
( SELECT candidate
FROM CandidateSkills
WHERE skill IN ('Running', 'Jumping')
GROUP BY candidate
HAVING COUNT(*) = 2 -- the number of skills
) AS sk
ON sk.candidate = c.candidate ;
答案 1 :(得分:1)
如果您想要所有技能和所有语言,只需计算乘法就足够了。
select c.id
from candidate c
join candidateLanguage cl on c.id = cl.candidateId
join language l on cl.languageId = l.id
join candidateSkill cs on c.id = cd.candidateId
join skill s on s.id = cs.skillId
group by c.id
having count(*) = 4
having
条件可以表示为
having count(*) =
(select count(*) from skill) * (select count(*) from language)
我该怎么办?
修改强>
如果您只需要语言和技能的子集,则可以对其进行过滤:
select c.id
from candidate c
join candidateLanguage cl on c.id = cl.candidateId
join language l on cl.languageId = l.id
join candidateSkill cs on c.id = cd.candidateId
join skill s on s.id = cs.skillId
where l.name in ('English', 'French')
and s.name in ('RUNNING', 'JUMPING')
group by c.id
having count(*) = 4
这里的不同之处在于,您只能计算符合条件的技能和语言。
答案 2 :(得分:0)
不优雅,但效率很高。
SELECT
*
FROM
Candidates c
WHERE
(SELECT COUNT(*)
FROM CandidateLanguages cl
WHERE cl.candidateId = c.candidateId AND cl.language in ('FRENCH', 'ENGLISH')
) = 2
AND
(SELECT COUNT(*)
FROM CandidateSkills cs
WHERE cs.candidateId = c.candidateId AND cs.skill in ('RUNNING', 'JUMPING')
) = 2
答案 3 :(得分:0)
如果您的数据查询可以写成“给我所有具有我们在表格中列出的所有已知技能的候选人,以及我们在不同表格中列出的所有已知语言”,而不仅仅是“所有候选人”英语和法语,以及跳跃和跑步“,你可以使用这些数据驱动的查询之一:
select
*
from
Candidates as C
where
(select count(*) from CandidateLanguages where CandidateName = C.Name) = (select count(*) from Languages)
and (select count(*) from CandidateSkills where CandidateName = C.Name) = (select count(*) from Skills)
go
select
*
from
Candidates
where
Name not in (
select
C.Name
from
(Candidates as C cross join Languages as L)
left join CandidateLanguages as CL on C.Name = CL.CandidateName and L.Name = CL.LanguageName
where
CL.CandidateName is null
)
and Name not in (
select
C.Name
from
(Candidates as C cross join Skills as S)
left join CandidateSkills as CS on C.Name = CS.CandidateName and S.Name = CS.LanguageName
where
CS.CandidateName is null
)
go
可以在LINQPad中测试的完整示例代码是available here。 (您可能必须创建空数据库)
答案 4 :(得分:-1)
select candidate-name,resulttblskills1.sumCOLRATIOSKILLS,resulttbllanguages1.sumCOLRATIOLanguages from candidates candidates1
join (select count(*) as sumCOLRATIOskills
from candidateskills skills1
where skills1.requiredskills in ('jumping','canoeing','mostlygoofing'
group by id
) as resulttblskills1 on resulttblskills1.id = candidates1.id
join (select count(*) as sumCOLRATIOLANGUAGES
from candidatelanguages languages1
where languages1.requiredlanguages in ('French','english','esparanto')
group by id ) as resulttbllanguages1 on resulttbllanguages1.id = candidates1.id
where resulttblskills1.sumCOLRATIOSKILLS > 1
and resulttbllanguages1.sumCOLRATIOLANGUAGES > 1
答案 5 :(得分:-2)
您正在描述候选人和技能之间以及候选人和语言之间的多对多关系。希望您的数据库具有必需的表。查询类似于:
select yourfields
from candidate c join candidateLanguage cl on c.id = cl.candidateId
join languages l on cl.languageId = l.id
join candidateSkill cs on c.id = cd.candidateId
join skill s on s.id = cs.skillId
where l.language in ('FRENCH', 'ENGLISH')
and s.skill in ('RUNNING', 'JUMPING')