2012-02-19 15 views
0

私はテーブルquestion、topicおよびquestion_has_topic(多対多の関係)を持っています。私のアプリケーションでは、管理者は自分のトピックでグループ分けされた質問の内訳を見て、システムから無作為に選択してテストを作成することを希望する人数を選択します。条件を満たすすべての条件に基づいて選択する(リレーショナル部門)

 
+-----------------------+---------------------+------------+ 
|  Topics   | Questions available | Selection: | 
+-----------------------+---------------------+------------+ 
| health,safety,general |     13 |   | 
| health    |     3 |   | 
| safety    |     7 |   | 
| general    |     1 |   | 
+-----------------------+---------------------+------------+ 

カウントがトピックの特定のグループ化のためにユニークです:
これは、彼らが参照テーブルの一種です。とにかく、彼らが選択をしたら、私はトピックのグループ化に対応する質問を選択するSQL文が必要です。 I.健康、安全、一般的な話題の3つの質問が必要な場合があります。
私はオンラインいくつかの研究をしていたと私は私がやろうとしているリレーショナル代数で、ここで除算として知られていることのTopicIDsの任意のグループ化のための私の試みであることを考える:

 
select questionid from question_has_topic 
where not exists (
    select questionid from question_has_topic 
    where topicid not in (8,9,10)) 

結果が空である、が、データベースに2つの質問がありますが、これらのトピックIDはすべて動作していないことを示しています。

SELECT questionid FROM question WHERE NOT EXISTS (
    SELECT topicid FROM topic WHERE topicid NOT IN (
     SELECT topicid FROM question_has_topic WHERE question.questionid = question_has_topic.questionid 
    ) AND topicid IN (8, 9, 10) 
); 

これは間違いなくはるかに高速です - - 私は、私は、これはあなたが書くしようとしていたものだと思うが、それはそれを行うための非常に非効率的な方法である。このlink

+0

質問が分かりませんでした。 – Luke101

+0

を言い換えることができますか?結果を見つけるには10通り以上の方法でこの質問を参照してください:[多人数関係でSQL結果をフィルタリングする方法](http://stackoverflow.com/questions/7364969/how-to- filter-sql-results-in-a-has-many-through-relation)、パフォーマンステスト(MySQLではなくPostgres用) –

答えて

2

EDIT:質問を誤読してから私の古い投稿を削除しました。


これは、私が過去に使用した手法である。

SELECT qht.questionid 
    FROM question_has_topic AS qht 
    WHERE qht.topicid IN (8,9,10) 
GROUP BY qht.questionid 
    HAVING COUNT(*) = 3 AND 
     COUNT(*) = (SELECT COUNT(*) FROM question_has_topic AS dupe 
        WHERE dupe.questionid = qht.questionid) 

3が与えられたグループ内のトピックの数に対応しています。これは、question_has_topicの各(questionid, topicid)ペアが一意であることを前提としています(多対多リレーションシップテーブル内にある必要があります)。

このクエリが動作する方法は、最初に、割り当てられたトピックのうちの少なくとも1つ(WHERE qht.topicid IN (8,9,10))を持つ質問を選択し、次にquestionidでグループ化します。最初のHAVING句(COUNT(*) = 3)は、特定の質問に3つのトピックすべてが割り当てられている場合にのみ真となります(この表では重複は許されないと仮定しているため)。 2番目のHAVING句は、質問に割り当てられているトピックの総数をチェックします。これは、例えば、質問にトピック8,9,10、および11が割り当てられている場合を防ぐためです。

+0

私はすでにこれを行っています。私が探していたものではありませんでした。私は悪いですが、私は問題を非常にはっきりと説明しませんでした。 –

+0

@artfuldodger:ほんとうに、私はもっと慎重に読むべきだった。私の編集をチェックしてください。 –

+0

@artfuldodger:私は今朝起きて、トピック(8,9,10,11)を持つ 'questionid'とのマッチングを防ぐために別の条件が必要であることに気付きました。 –

2

から例を以下ました

SELECT * 
FROM question_has_topic t1 
INNER JOIN question_has_topic t2 
    ON t1.questionid = t2.questionid AND t2.topicid = 9 
INNER JOIN question_has_topic t3 
    ON t2.questionid = t3.questionid AND t3.topicid = 10 
WHERE t1.topicid = 8; 

更新:もっと簡単な答えがあることを知っていました。チェランの方法ははるかに簡単で、INNER JOINよりも少し速く実行する必要があります。彼の答えを受け入れてください。

+0

ありがとう、私が探していたものです。これまでの2番目のソリューションで提案した方法でやっていましたが、これはもっと効率的なソリューションだとは思いませんでした。 –

+0

あなたが実行しようとしていた関係分割の形式は、リンクした例のようなセット全体の存在をチェックするときにのみ本当に適しています。だから、それをあなたのスキーマに関連付けると、あらゆるトピックを持つ質問を見つけることは有益でしょう。 – nnichols

+0

このメソッドは、通常、 'JOIN'を使って' GROUP BY'より高速です。しかし、それはデータの分布、あなたが求めている質問の数(3または20?)などによって異なります。 –

関連する問題