Выберите курсы, которые полностью удовлетворяют заданному списку обязательных условий

Я пытаюсь написать 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, поэтому, пожалуйста, извините меня, если есть проблема с моей структурой таблицы и т. д., или если это, казалось бы, простой вопрос. Я искал все, что мог, но могу найти только то, что кажется решением, обратным этой проблеме.

Кажется, мне нужно сделать разницу наборов:

  • Создайте набор курсов, которые имеют предварительные условия (для каждого предварительного условия?)
  • Создайте набор курсов, которые не имеют предварительных условий
  • Выполните операцию с разницей наборов: выберите все, что присутствует в первом наборе, и не присутствует во втором. Кажется, это просто, но теперь я запутался с соединительной таблицей и тем, как справиться с этим во многих предварительных условиях.

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

Например, если заданы предварительные условия «Искусство», «Английский язык», «Психология», то единственная строка, которая должна быть возвращена, — это строка для курса 2 (предварительные требования более чем выполнены).

Спасибо


person lberezy    schedule 19.12.2013    source источник
comment
Какую СУБД (SQL Flavor) вы используете?   -  person PM 77-1    schedule 19.12.2013
comment
ваша вторая строка в CoursePrerequisites дублируется. Это так или это опечатка? Кстати, неплохое оформление :)   -  person Jorge Campos    schedule 19.12.2013
comment
Пожалуйста, покажите желаемый результат на основе ваших данных образца.   -  person PM 77-1    schedule 19.12.2013
comment
Я использую MySQL для RDBMS. Я сделаю желаемый вывод более ясным. Хорхе, повторяющиеся строки в таблице CoursePrerequisite — это не опечатка. Эта таблица выступает в качестве соединительной таблицы для облегчения связи «многие ко многим» между курсами и их предварительными условиями. Если идентификатор курса указан 2 раза, это означает, что он имеет 2 обязательных условия. Я считаю, что я правильно настроил таблицы и для этого отношения (ссылки по внешнему ключу и т. д.).   -  person lberezy    schedule 19.12.2013
comment
Хорхе, извини, ты был прав. Была повторяющаяся строка (сейчас исправлено). Я пришел к выводу, что вы думали о том, что поле Course_FK имеет дубликаты.   -  person lberezy    schedule 19.12.2013
comment
Потому что об этом не упоминалось ранее - по логике вещей, вероятно, должна быть только одна таблица course без prerequisite (ведь предварительные условия — это тоже курсы, верно?). Вы сохраняете текущую таблицу перекрестных ссылок в основном как есть, просто переключаетесь туда, куда указывает другой внешний ключ.   -  person Clockwork-Muse    schedule 01.01.2014
comment
На самом деле, в этом случае набор пререквизитов больше, чем у курсов (у курса может быть обязательное условие собеседования или какой-то результат теста › какое-то значение, как и у другого курса). Тем не менее, спасибо за ваш конструктивный вклад!   -  person lberezy    schedule 02.01.2014


Ответы (3)


Мне удалось решить проблему с помощью следующего запроса (а также немного узнать о 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;
person lberezy    schedule 01.01.2014

1, ВЫБЕРИТЕ Course_FK, COUNT(1) AS Num FROM CoursePrerequisites GROUP BY Course_FK

и сохраните результат во временной таблице temp_a.

2, ВЫБЕРИТЕ Course_FK ,COUNT(1) AS Num FROM CoursePrerequisites a INNER JOIN Prerequisites b ON a.Prerequisite_FK=b.Id GROUP BY Course_FK

и сохраните результат во временной таблице temp_b.

3, ВЫБЕРИТЕ a.Course_FK FROM temp_a a INNER JOIN temp_b b ON a.Course_FK=b.Course_FK AND a.Num=b.Num

это будет идентификатор квалифицированного курса

person xiaoyifang    schedule 17.02.2014

person    schedule
comment
Должен ли быть «И» перед ключевыми словами «НЕ СУЩЕСТВУЕТ»? - person lberezy; 19.12.2013