6

私はテーブルを持っています:

  • Candidates
  • CandidateLanguages
  • CandidateSkills

各候補者は、複数の言語と複数のスキルを持っている場合があります

だから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') 

上記の 2 つの候補のうち、「FRED」のみが返されます。

Language and Skills テーブルから複数のレコードを選択しようとすると問題が発生することは理解しており、結合が必要になる可能性があると思いますが、今は迷っています...

4

6 に答える 6

4

あなたが解決しようとしている問題はRelational Divisionと呼ばれます。

この記事を参照してください:分断された私たちの立場: リレーショナル除算の SQL と、それを解決するいくつかの方法については、この質問: SQL の結果をフィルター処理して多数のスルー関係にする方法

それを解決する1つの方法(一般的に最も効率的です):

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それぞれに 2 つの派生テーブルを使用することです。

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 ;
于 2013-07-06T20:03:29.263 に答える
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

ここでの違いは、基準に一致するスキルと言語のみをカウントできることです。

于 2013-07-06T20:03:43.930 に答える
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
于 2013-07-06T20:05:02.700 に答える
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でテストできる完全なサンプル コードは、こちらから入手できます(空のデータベースを作成する必要がある場合があります)

于 2013-07-06T20:10:24.483 に答える
-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
于 2013-07-06T20:16:18.167 に答える