2012-02-19 63 views
0

我有表格問題,主題和question_has_topic(多對多關係)。在我的應用程序管理員中,查看按主題分組的問題的細目,並選擇他們希望系統隨機選擇以創建測試的人數。
這是他們看到的那種表:根據所有符合條件進行選擇(關係部門)

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

計數爲主題的具體分組是獨一無二的。無論如何,一旦他們做出選擇,我需要一個SQL語句來選擇與給定的主題分組相對應的問題。 也就是說我可能需要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,這些主題ID告訴我這是行不通的。我下面從這個link

+0

我不明白這個問題。你可以改述 – Luke101 2012-02-20 02:51:30

+0

另請參閱此問題與超過10種方式來查找結果:[如何過濾SQL結果中的一個通過多關係](http://stackoverflow.com/questions/7364969/how-to- filter-sql-results-in-a-many-through-relation)以及性能測試(針對Postgres,而不是MySQL)。 – 2012-02-20 07:18:42

回答

2

編輯:刪除了我以前的帖子,因爲我誤讀了這個問題。


這是我在過去使用的技術:

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)對都是唯一的(它應該位於多對多關係表中)。

此查詢的工作方式是首先選擇至少包含一個所需主題的問題(WHERE qht.topicid IN (8,9,10)),然後按questionid進行分組。第一個HAVING子句(COUNT(*) = 3)只有在給定問題分配了全部三個主題的情況下才會成立(因爲我們假設此表中不允許有重複項)。第二個HAVING子句檢查分配給問題的主題總數。這是爲了防範,例如,一個問題可能會分配主題8,9,10和11。

+0

我已經完成了這個工作,而不是我一直在尋找的東西。我的壞但我沒有很清楚地解釋這個問題。 – 2012-02-20 06:52:52

+0

@artfuldodger:哎呦,我應該仔細閱讀。檢查我的編輯。 – 2012-02-20 07:06:35

+0

@artfuldodger:我今天早上醒來,意識到需要另外一個條件來阻止,例如,匹配包含主題(8,9,10,11)的'questionid'。 – 2012-02-20 15:26:11

2

我想這是你想要寫的例子,但它是那麼這是一種非常低效的方式 -

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

這絕對是更快 -

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; 

更新:我知道有一個更簡單的答案。 Cheran的方法要簡單得多,並且應該比INNER JOIN運行得稍快。請接受他的回答。

+0

謝謝,這就是我一直在尋找。我按照你之前在第二種解決方案中所建議的方式來做 - 我沒有意識到這是更高效的解決方案。 – 2012-02-20 06:54:31

+0

您試圖執行的關係部門的形式僅適用於檢查整個集合的存在情況,例如您在鏈接的示例中。因此,將它與您的模式相關聯,找到每個主題都會很有用的問題。 – nnichols 2012-02-20 09:07:06

+0

該方法使用'JOIN'通常比'GROUP BY'更快。但是這取決於數據分佈,你需要詢問多少個問題(3或20?)等。 – 2012-02-20 22:38:26