选择完全满足给定先决条件列表的课程
Posted
技术标签:
【中文标题】选择完全满足给定先决条件列表的课程【英文标题】:Select courses that are completely satisfied by a given list of prerequisites 【发布时间】:2013-12-19 00:58:05 【问题描述】:我正在尝试编写一个 SQL 查询,该查询将返回一个人有资格参加的课程列表,给出他们已完成科目的列表(用作先决条件)。
我的数据库是这样布局的。
Prerequisite:
+---------------+---------------+
| Id | Name | (Junction table)
|---------------|---------------| CoursePrerequisites:
| 1 | Maths | +---------------+---------------+
| 2 | English | | Course_FK | Prerequisite_FK
| 3 | Art | |---------------|---------------|
| 4 | Physics | | 1 | 1 |
| 5 | Psychology | | 1 | 2 |
+-------------------------------+ | 2 | 3 |
| 2 | 5 |
Course: | 5 | 4 |
+---------------+---------------+ +---------------v---------------+
| Id | Name |
|---------------|---------------|
| 1 | Course1 |
| 2 | Course2 |
| 3 | Course3 |
| 4 | Course4 |
| 5 | Course5 |
+---------------v---------------+
我一直在试验如下查询:
SELECT DISTINCT C.*
FROM Course C
INNER JOIN JNCT_Course_Prerequisites cp
ON C.Id = cp.Course_FK
WHERE cp.Prerequisite_FK IN (SELECT Prerequisites.Id FROM Prerequisites Where Name = 'Art' AND Name = etc etc)
但是,这会返回以艺术为先决条件的任何课程,而不仅仅是由给定的先决条件列表完全满足的课程。例如。它将返回课程 2,仅将艺术作为学生的先决条件,即使该课程还需要心理学。
我对 SQL 很陌生,所以如果我的表格布局等有问题,或者这是一个看似简单的问题,请原谅。我一直在尽我所能四处寻找,但只能找到似乎是解决这个问题的反面的方法。
看来我需要做一些不同的设置:
构建一组具有先决条件的课程(针对每个先决条件?) 构建一组没有先决条件的课程 执行不同的集合操作:选择所有存在于第一个集合中且不存在于第二个集合中 看起来很简单,但我现在对联结表以及如何在许多先决条件下处理它感到困惑。我希望返回至少完全满足给定先决条件列表的行,而不是包含至少一个先决条件的行。
例如,如果给出了先决条件“Art”、“English”、“Psychology”,则应该返回的唯一行是 Course2 的行(先决条件不满足)。
谢谢
【问题讨论】:
您使用的是哪种 RDBMS(SQL 风格)? 您在 CoursePrerequisites 上的第二行是重复的。这是对的还是错字?顺便说一句,格式很好:) 请根据您的示例数据显示所需的输出。 我将 mysql 用于 RDBMS。我将使所需的输出更清晰。 Jorge,CoursePrerequisite 表中的重复行不是错字。该表作为连接表服务器,以促进课程与其先决条件之间的多对多关系。如果一个课程 ID 被列出 2 次,则意味着它有 2 个先决条件。我相信我也为这种关系正确设置了表格(外键引用等)。 豪尔赫,对不起,你是对的。有一条重复的行(现已修复)。我立即得出结论,您正在考虑 Course_FK 字段有重复项。 【参考方案1】:SELECT * FROM Course C LEFT JOIN Course_Prerequisites cp ON C.Id = cp.Course_FK
WHERE Prerequisite_FK IN (SELECT Prerequisites.Id FROM Prerequisites Where Name = 'Art' OR Name = etc etc)
NOT EXISTS
(SELECT * FROM Course C LEFT JOIN Course_Prerequisites cp ON C.Id = cp.Course_FK
WHERE Prerequisite_FK NOT IN (SELECT Prerequisites.Id FROM Prerequisites Where Name = 'Art' OR Name = etc etc))
【讨论】:
“NOT EXISTS”关键字前是否应该有一个“AND”?【参考方案2】:我能够通过以下查询解决问题(并且在此过程中还了解了一些关于 GROUP_CONCAT 的知识)。 GROUP_CONCAT 并不是真正需要的,但可以使输出更清晰。这也取决于 在“GROUP BY Course.id”上 - 如果不需要,可以将其删除。此解决方案执行必要的集合差异,并仅选择至少满足先决条件的课程。
我还是很陌生,所以如果有什么可以做得更好的,请告诉我。
SELECT Course.id, course.Name, GROUP_CONCAT(DISTINCT Prerequisite.Name) AS 'Prerequisite Name(s)'
FROM Course
LEFT JOIN CoursePrerequisites ON Course.id = CoursePrerequisites.Course_FK
LEFT JOIN Prerequisite ON Prerequisite.id = CoursePrerequisites.Prerequisite_FK
WHERE NOT EXISTS
(SELECT 1
FROM CoursePrerequisites
WHERE Course.id = CoursePrerequisites.Course_FK
AND CoursePrerequisites.Prerequisite_FK NOT IN (SELECT Prerequisite.id FROM Prerequisite Where Name = 'Art' OR Name = 'English' OR Name = 'Psychology''))
GROUP BY Course.id;
【讨论】:
【参考方案3】:1, SELECT Course_FK ,COUNT(1) AS Num FROM CoursePrerequisites GROUP BY Course_FK
并将结果存储在临时表 temp_a 中。
2, SELECT Course_FK ,COUNT(1) AS Num FROM CoursePrerequisites a INNER JOIN 先决条件 b ON a.Prerequisite_FK=b.Id GROUP BY Course_FK
并将结果存储在临时表 temp_b 中。
3, SELECT a.Course_FK FROM temp_a a INNER JOIN temp_b b ON a.Course_FK=b.Course_FK AND a.Num=b.Num
这将是合格课程的 ID
【讨论】:
以上是关于选择完全满足给定先决条件列表的课程的主要内容,如果未能解决你的问题,请参考以下文章