2013-07-06 1 views
6

私は過去に単純なSQL文しか使用していませんでしたが、突然自分自身がもっと複​​雑なことをしなければならず、自分の深みから抜け出しています。どんな助けもありがとう。 複雑(私にとって)SQL文

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

  • Candidates
  • CandidateLanguages
  • CandidateSkills

各候補者は1つの以上の言語とCandidateため

だから、1つの以上のスキルを有することができます"FRED"、彼の記録CandidateLanguagesでdsは

FRED - ENGLISH 
FRED - FRENCH 
CandidateSkills

と彼のレコードはCandidateLanguagesで "JIM" 彼のレコードは

JIM - ENGLISH 

CandidateSkillsで彼のレコードのかもしれ

FRED - RUNNING 
FRED - JUMPING 

Candidateためのものであってもよいかもしれ

JIM - RUNNING 

私のクエリでは、複数のスキルと言語にマッチする候補を選択する必要があります。英語で例えばので

は...

を選択したすべての言語を話すと、選択したスキルのすべてを持っている候補者のすべてを選択するか、別の方法を置く....

上記の二つの候補の
SELECT ALL candidates WHERE 
(language = 'FRENCH' AND language is 'ENGLISH') AND 
(skill = 'RUNNING' AND skill = 'JUMPING') 

、これはのみから複数のレコードを選択しようとすると問題があることを私は理解し

を「FRED」を返す必要があります言語とスキルテーブルと私はそれが参加すると思うが必要になることがありますが、今は失われています.......

をご入力ありがとうございました - それはずっと

+0

は、クエリを逆転しようとしたことがありますか? 「スキルの1つが欠落しているか、または欠落しているすべての候補者を教えてください」場合によっては、問題を再現することで、他の/より良い解決策が得られる場合もあります。適切な場所に「not」を置くと、必要なデータが得られるはずですが、「欠けていない」部分は、「having having」部分よりもSQLクエリとして定式化する方が簡単かもしれません。 –

+0

thats 60 points .. 14より多く、彼は毎日の制限に達すると、明日を待たなければならない。 – user1974729

+0

@ user1974729:質問の6 upvotesは30の担当者、60ではないことを意味する。 –

答えて

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の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 ; 
+3

15言語と60スキルがあればどうなりますか? – gaborsch

+1

@ GaborSch次に、60 + 15 = 75の結合があります。私は、(ほとんどの場合) 'GROUP BY'クエリよりもはるかに効率的であることを保証します。 –

+0

ご協力いただきありがとうございます。大変感謝しています。 – user2556881

-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') 
+4

そのクエリは説明と同じではなく、両方のスキルを持つ言語を話す人が返されます – AD7six

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) 

私はここで何をしますように表現することができますか?カウントがすべての組み合わせがあり、この候補者のために、その後(スキルの数)*(言語の数)に等しい場合、すべての可能な候補言語スキルリスト

  • は、候補
  • によってそれらをグループ化
  • トリプレット現在

EDIT:

あなただけの言語やスキルのサブセットをしたい場合、あなたはそれをフィルタリングすることができます。

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 

違い、ここでは、あなたの条件に一致しているだけでこれらのスキルや言語を数えることができるということです。

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 
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です。 (あなたが空のデータベースを作成する必要があります)

-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 
+0

'resulttblskills1'と' resulttblskills2'に 'id'カラムがありますか? – Camouflage

+0

yaうーん、IDでグループ分けして、各IDの合計を取得し、主キーで合計テーブルを結合する。 – user1974729

+1

選択行には表示されません。おそらくそこに追加するのを忘れていました。また、 'sumCOLRATIOSKILLS> 1 'の条件も修正したいと思います。 – Camouflage