繁体   English   中英

SQL查询以选择满足先决条件的主题

[英]SQL Query to select subjects that satisfy prerequisite requirements

我有以下表格:

课程

+----------+-------------------------+
| course_id |      course_name       |
+-----------+------------------------+
|        1  |                   s001 |
|        2  |                   s002 |
|        3  |                   s003 |
|        4  |                   s004 |
+-----------+------------------------+

COURSE_PREREQUISITES

+----------+-------------------------+
| course_id | prerequisite_course_id |
+-----------+------------------------+
|        3  |                   2    |
+-----------+------------------------+
|        4  |                   1    |
+-----------+------------------------+  
|        4  |                   2    |
+-----------+------------------------+
|        4  |                   3    |
+-----------+------------------------+

我的问题是:给定学生已完成的课程ID列表,我如何获得该学生有资格参加的课程列表?

如果学生已完成course_id 2,则查询应返回课程:1,(因为它没有先决条件)和3,但不是4,因为4也有1,3作为先决条件。

尝试解决方案

对于已完成课程2的学生,我已经尝试使用IN语句:

SELECT DISTINCT course_id FROM COURSE_PREREQUISITES
  WHERE prerequisite_course_id IN (2) 

但是它显然失败了,因为它返回了至少满足我所不需要的一个前提条件的所有课程。

我遇到了类似的问题: 选择与list中所有项目匹配的行 但是提供的解决方案在我的情况下不起作用,因为课程的先决条件数量是不确定的。

最后,我还想知道NOSQL数据库(couchDB,mongoDB)是否更适合此类问题。

accept cid;

select a.course_id from 
(select course_id, max(prerequisite_course_id) as prerequisite_course_id from course_prerequisites 
group by course_id 
having count(*)=1) a 
where a.prerequisite_course_id=&cid
union
select b.course_id from
(select course_id from course where course_id!=&cid) b
left join course_prerequisites c 
on b.course_id=c.course_id where c.course_id is null;

联合之前的前半部分将获取具有输入的输入作为先决条件的课程的course_id,而联合之后的另一半将选择没有任何先决条件的课程。

这在oracle中有效。 接受是在运行时获取输入。 对于其他数据库,您可以忽略accept语句,并使用course_id代替&cid。

COURSE左转到COURSE_PREREQUISITES

select c.*
from course c left join course_prerequisites cp
on cp.course_id = c.course_id
where 
  c.course_id <> 2
  and 
  (
    cp.prerequisite_course_id is null
    or
    (
      cp.prerequisite_course_id = 2
      and
      (select count(*) from course_prerequisites where course_id = c.course_id) = 1
    )
  ) 
order by c.course_id

观看演示

假设您有两个输入课程(1,2)则可以使用以下查询

select distinct c.course_id 
from courses c
left join course_prerequisites cp on cp.course_id = c.course_id
group by c.course_id
having count(case when cp.prerequisite_course_id not in (1,2) then 1 end) = 0

假设您只关心具有先决条件的课程,那么这应该会得到您想要的:

select cp.course_id
from course_prerequisites cp
group by cp.course_id
having count(*) = sum( prerequisite_course_id in ( <list of taken courses goes here> ) );

sum()正在计算与给定课程的前提条件匹配的课程数量。 count() = count(*)要求与学生所修课程匹配。

然后,有些课程没有先决条件。 所以:

(select cp.course_id
 from course_prerequisites cp
 group by cp.course_id
 having count(*) = sum( prerequisite_course_id in ( <list of taken courses goes here> ) )
) union all
(select c.course_id
 from courses c
 where not exists (select 1
                   from course_prerequisites cp
                   where cp.course_id = c.course_id
                  )
);

实际上,您可以在没有union all情况下执行此操作。 。:

select c.course_id
from courses c left join
     course_prerequisites cp
     on c.course_id = cp.course_id
group by c.course_id
having count(cp.course_id) = sum( cp.prerequisite_course_id in ( <list of taken courses goes here> ) );

此处的逻辑与第一个查询中的逻辑相同,除了其中包括没有先决条件的课程,并且count(cp.course_id)可以为0

在MySQL中,您可以使用FIND_IN_SET通过此查询获取所需的结果,该查询将完成的课程数量与每个课程的先决条件数量进行比较。 结果包括没有先决条件的课程(如果学生尚未完成该课程)。

SET @courses_completed = '2';
SELECT c.course_id
FROM course c
LEFT JOIN course_prerequisites p ON p.course_id = c.course_id
WHERE NOT FIND_IN_SET(c.course_id, @courses_completed)
GROUP BY c.course_id
HAVING SUM(COALESCE(FIND_IN_SET(p.prerequisite_course_id, @courses_completed), 0) > 0) = COUNT(p.prerequisite_course_id);

输出:

course_id
1
3

我做了一个关于SQLFiddle演示用的各种值@courses_completed展示课程的学生可享有可能的变体。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM