SQL-запрос для выбора предметов, которые удовлетворяют предварительным требованиям - PullRequest
0 голосов
/ 10 февраля 2019

У меня есть следующие таблицы:

КУРС

+----------+-------------------------+
| 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    |
+-----------+------------------------+

Мой вопрос: Учитывая список идентификаторов курсов, пройденных студентом, как я могу получить список курсов, в которых студент имеет право участвовать?

Пример

Если учащийся выполнил course_id 2, запрос должен возвращать курсы: 1 (поскольку он не имеет предварительных условий) и 3, но не 4, так как 4 также имеет 1,3 как предварительные условия.

Попытка найти решение

Я пытался использовать такое утверждение IN, как для студента, который закончил курс 2:

SELECT DISTINCT course_id FROM COURSE_PREREQUISITES
  WHERE prerequisite_course_id IN (2) 

, но оно, очевидно, не удаетсятак как он возвращает все курсы, которые удовлетворяют по крайней мере одному предварительному условию, а это не то, что мне нужно.

Я столкнулся с подобным вопросом: Выберите строки, соответствующие всем элементам в списке .Но предоставленное решение не работает в моем случае, так как количество предпосылок для курса не является фиксированным.

Наконец, я также хотел бы знать, подходят ли базы данных NOSQL (couchDB, mongoDB) для задачкак это.

Ответы [ 5 ]

0 голосов
/ 10 февраля 2019

В 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, чтобы показать возможные варианты курсов, на которые имеет право студент.

0 голосов
/ 10 февраля 2019

Если вы заботитесь только о курсах с предварительными реквизитами, это должно дать вам то, что вы хотите:

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.

0 голосов
/ 10 февраля 2019

Если у вас есть, например, два ввода (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
0 голосов
/ 10 февраля 2019
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 для курса, который имеет входные данные в качестве предварительного условия, а вторая половина после объединения должна выбрать курсы, которые не имеют никаких предварительных условий.

Это работает в оракуле.Принять, чтобы получить ввод во время выполнения.Для других БД вы можете проигнорировать оператор accept и передать вместо него курс__id.

0 голосов
/ 10 февраля 2019

С левым соединением от 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

См. Демоверсию

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...