2012-02-19 33 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