根据满足的所有条件进行选择(关系师)

时间:2012-02-19 23:23:27

标签: mysql sql relational-algebra

我有表格问题,主题和question_has_topic(多对多关系)。在我的应用程序管理员中,查看按主题分组的问题的细分,并选择他们希望系统随机选择创建测试的人数。 这是他们看到的那种表格:

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

计数对于特定的主题分组是唯一的。无论如何,一旦他们做出选择,我需要一个SQL语句,它将选择与给定的主题分组相对应的问题。 即我可能需要3个问题,其主题是健康,安全和一般。我在网上进行一些研究,我认为我正在尝试做的事情被称为关系代数中的分歧,这是我尝试的任意分组的主题:

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

结果是空的,尽管数据库中有两个问题,其中包含所有这些主题ID,这些问题告诉我这不起作用。我正在关注此link

中的示例

2 个答案:

答案 0 :(得分: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快一些。请接受他的回答。

答案 1 :(得分: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对应于给定组中的主题数。这假定(questionid, topicid)中的每个question_has_topic对都是唯一的(它应该在多对多关系表中)。

此查询的工作方式是首先选择至少分配了一个所需主题的任何问题(WHERE qht.topicid IN (8,9,10)),然后按questionid进行分组。第一个HAVING子句(COUNT(*) = 3)只有在给定的问题分配了所有三个主题时才能为真(因为我们假设此表中不允许重复)。第二个HAVING子句检查分配给问题的主题总数。这是为了防止例如一个问题可能分配了主题8,9,10和11的情况。