Мне нужен эксперт JPA / SQL: запрос EXISTS на Inner Join возвращает неверный результат - PullRequest
0 голосов
/ 18 марта 2020

У меня есть три таблицы, и я хочу:

Select всех учащихся from первой таблицы,

, которые имеют хотя бы одну связь со школой в округе '999' в вторая таблица

and хотя бы одна связь с учителем с помощью social_number '101'

and хотя бы одна связь с учителем с номером '103' в третьей таблице.

Таблицы связаны через вторую таблицу.

my three tables

Я создал онлайн-компилятор sql, чтобы показать проблему: http://tpcg.io/FIoO79xi

Этот запрос работает нормально и, как и ожидалось, пока я не добавлю третью команду EXISTS, где я ищу соединение с учителем «103». Тогда он больше не возвращает ученика А, хотя у него есть связь с учителем «103»

Я нашел обходной путь, добавив joins в Exists sub-query: http://tpcg.io/0sza7t5g
но так как в моих реальных таблицах базы данных много миллионов записей, это привело бы к объединению трех таблиц в каждой строке, через которую проходит sub-query, и это может занять очень много времени, если он найдет подходящую запись только в конце Таблица.

Я думаю, что проблема здесь в sub-query: WHERE th1.school_id = th.school_id, где я пытаюсь найти связь между третьим учителем таблицы и таблицей в начале, соединенной вместе. Если я ищу соединение с учителем 102 вместо 103, запрос работает и возвращает ученика A: http://tpcg.io/2tHIEk3V Поскольку учителя 101 и 102 имеют один и тот же school_id.

Но как я могу напишите это по-другому, чтобы запрос также нашел ученика А, когда я ищу соединение с учителем 101 и 103? Студент А имеет связь с обоими, поэтому это должно быть как-то возможно с существующим ...

Добавить: Я не могу использовать три отдельных запроса, а затем использовать команду Intersect для них, так как я перевод этого SQL в JPA запрос. JPA не знает, пересекаются ...

Ответы [ 4 ]

2 голосов
/ 18 марта 2020

1-е условие:

хотя бы одно соединение со школой в округе '999' во второй таблице

требуется соединение student с school. 2-е и 3-е условия:

хотя бы одна связь с учителем с social_number '101' и хотя бы один учитель с номером «103»

необходимо 2 отдельные объединения student до school и teacher:

SELECT s.name 
FROM student s
INNER JOIN school sc on s.student_id = sc.student_id AND sc.district = 999
INNER JOIN school sc1 on s.student_id = sc1.student_id
INNER JOIN teacher t1 on t1.school_id = sc1.school_id AND t1.social_number = 101
INNER JOIN school sc2 on s.student_id = sc2.student_id
INNER JOIN teacher t2 on t2.school_id = sc2.school_id AND t2.social_number = 103

Обратите внимание, что такое условие, как social_number in (101, 103), не будет работать, поскольку оно будет возвращать результаты, даже если выполнено только одно из условий. Вот почему вам нужно 2 соединения с school и teacher. Также все соединения должны быть inner, потому что вы хотите выполнить все 3 условия. Смотрите демо . Результаты:

| name |
| ---- |
| A    |
1 голос
/ 18 марта 2020

Вам нужно 2 присоединения к столу учителя

SELECT name 
FROM student
left JOIN school sc1 on #student.student_id = sc1.student_id
left JOIN teacher th1 on sc1.school_id = th1.school_id and th1.social_number=101
left JOIN teacher th2 on sc1.school_id = th2.school_id and th1.social_number=103
where sc1.district=999 
0 голосов
/ 18 марта 2020

http://tpcg.io/eGeWjkOf

Целостное присоединение не требуется, когда мы просим о соединении между учителем и учеником в дополнительном предложении WHERE. Затем Exists subquery выглядит следующим образом: вместо соединения я использую дополнительный where, чтобы убедиться, что значение teacher.school_id совпадает с идентификатором school.school_id школы, в которую идет ученик:

EXISTS (
SELECT *
FROM teacher th
WHERE th.social_number = '103'
AND th.school_id in (SELECT school_id FROM school WHERE student_id = student.student_id ))
0 голосов
/ 18 марта 2020

Почему так сложно?

`SELECT name 
FROM student
LEFT JOIN school sc1 on student.student_id = sc1.student_id
LEFT JOIN teacher th1 on sc1.school_id = th1.school_id
WHERE sc1.district = '999'
AND th1.social_number in('101','103')`

не помогает?

...