【问题标题】:selecting based on all conditions being met (relational division)根据满足的所有条件进行选择(关系划分)
【发布时间】:2012-02-19 23:23:27
【问题描述】:

我有表格 question、topic 和 question_has_topic(多对多关系)。在我的应用程序中,管理员会看到按主题分组的问题的细分,他们会从每个问题中选择多少,希望系统随机选择来创建测试。
这是他们看到的那种桌子:

+------------------------+----------+--- ---------+ |话题 |可用问题 |选择: | +------------------------+----------+--- ---------+ |健康、安全、通用| 13 | | |健康 | 3 | | |安全 | 7 | | |一般| 1 | | +------------------------+----------+--- ---------+

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

从 question_has_topic 中选择 questionid 不存在的地方( 从 question_has_topic 中选择 questionid 其中 topicid 不在 (8,9,10))

结果为空,尽管数据库中有 2 个问题具有所有这些主题 ID,这告诉我这不起作用。我是按照这个link的例子来的

【问题讨论】:

标签: mysql sql relational-algebra


【解决方案1】:

编辑:因为我误读了问题,所以删除了我的旧帖子。


这是我过去使用过的一种技术:

  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。

【讨论】:

  • 我已经完成了这项工作,但并不是我想要的。我的不好,我没有很清楚地解释这个问题。
  • @artfuldodger:哎呀,我应该更仔细地阅读。检查我的编辑。
  • @artfuldodger:我今天早上醒来,意识到需要另一个条件来阻止,例如,匹配具有主题 (8,9,10,11) 的 questionid。
  • 我很感激。谢谢。我将使用此方法,但假设我选择一组供用户选择,即主题 8、9、10 中的 3 个问题,但之后我需要仅从主题 8 中说出 10 个问题——以避免重新选择相同的问题我跟踪使用的 id 并使用 where not in (usedids) 子句来防止它发生。还有其他方法吗?
  • 您可以通过将and questionid not in (usedids) 添加到having 子句来实现该效果。由于 having 是在 group by 子句之后评估的,因此不会干扰此技术的意图。
【解决方案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 稍快。请接受他的回答。

【讨论】:

  • 谢谢,这正是我想要的。我是按照您之前在第二个解决方案中建议的方式进行操作的——不过我没有意识到这是更有效的解决方案。
  • 您尝试执行的关系除法形式仅在检查整个集合是否存在时才真正适合,例如在您链接到的示例中。因此,将其与您的架构相关联,查找包含每个主题的问题会很有用。
  • 这种方法,JOIN 通常比GROUP BY 快​​。但这取决于数据分布、您要查询的问题数量(3 个还是 20 个?)等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
  • 2012-01-07
  • 2020-04-12
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多