#sql #postgresql #join #relational-division #in-subquery
#sql #PostgreSQL #Присоединиться #реляционное разделение #Подзапрос
Вопрос:
У меня есть таблица Students, в которой есть следующие столбцы
id
student_name
И таблица курсов
id
student_id //a foreign key
course_name
credits
Это отношение «один ко многим» (у одного студента может быть несколько курсов).
Я хочу перечислить всех студентов, у которых есть эти 2 курса
first course: course_name -> math , credit -> 5
second course: course_name -> history , credit -> 3
Пожалуйста, обратите внимание, что каждый студент должен пройти по крайней мере эти два курса.
Я могу получить то, что хочу, присоединившись к таблице Courses дважды (один раз для первого курса и еще один для второго курса), но в случае, если я захочу добавить еще один курс к условию, мне нужно будет присоединиться еще раз.
Так что, пожалуйста, не могли бы вы направить меня к другому подходу.
Комментарии:
1. Вы хотите, чтобы у каждого учащегося были именно эти два курса или, по крайней мере , эти два курса (но может быть больше)
2. Не связано с вашим вопросом, но разве это не должно быть отношением «многие ко многим»? Один курс может содержать несколько студентов, и один студент записывается на несколько курсов
3. По крайней мере, эти 2 курса
4. Правда, лучше быть «многие ко многим», но я просто использовал этот пример, чтобы упростить вопрос
Ответ №1:
Решает ли это вашу проблему? Я считаю все вхождения для ваших ожидаемых курсов, и сумма должна быть 2
.
SELECT
s.id
FROM students s
JOIN courses c
ON c.student_id = s.id
GROUP BY s.id
HAVING SUM(
((c.course_name = 'math' AND c.credits = 5)
OR
(c.course_name = 'history' AND c.credits = 3))::int
) = 2
В качестве альтернативы SUM(condition::int)
вы могли бы использовать COUNT()
FILTER
предложение with a:
HAVING COUNT(*) FILTER (WHERE
(c.course_name = 'math' AND c.credits = 5)
OR
(c.course_name = 'history' AND c.credits = 3)
) = 2
Комментарии:
1. спасибо за усилия, которые вы приложили к ответу, в демо-версии это выглядит нормально, но чтобы заставить его работать в моем случае, я пытаюсь понять, как сумма равна 2, когда вы используете ИЛИ, поэтому я попробовал это
select (true or true)::int as x
, и это дает мне 1, как я и ожидал. Не могли бы вы объяснить, как вы получаете сумму 2?2. Вы правы: условие bool дает 0 или 1. Поскольку
student _id == 2
(в моей скрипке) соответствует этому условию дважды (первое дляmath
, второе дляhistory
записи), сумма двух совпадений равна 2. Итак, если вам нужно добавить третье условие, сумма должна быть равна 3, потому что таблица должна соответствовать условию три раза. Я добавил промежуточный шаг здесь: dbfiddle.uk /…3. Спасибо за объяснение и элегантное решение