У меня есть пять (5) таблиц: студенты, предметы, period_one, period_two и period_three. Я выполняю левое соединение, чтобы выбрать значения из этих пяти таблиц:

Стол студентов (студенты)

  student_id    | Name
  --------------|-------
  1             |John
  2             |Peter
  3             |Flomo 

Таблица предметов (предметы)

  subject_id       |SubjectName
  -----------------|-------
  math101          |Mathematics
  eng201           |English
  lang303          |Language Arts

Таблица первого периода (period_one)

  id|student_id |subject_id| score
  --------------|----------|-----
  1 |1          | math101  |99
  2 |2          | eng201   |88
  3 |3          | lang303  |77 

Таблица периода два (period_two)

  id|student_id |subject_id| score
  --------------|----------|-----
  1 |1          | math101  |100
  2 |2          | eng201   |60
  3 |3          | lang303  |65 

Таблица периодов три (period_three)

  id|student_id |subject_id| score
  --------------|----------|-----
  1 |1          | math101  |71
  2 |2          | eng201   |51
  3 |3          | lang303  |71

Вот запрос, который я использую для получения записей Query1 :

SELECT period_one.student_id, period_one.subject_id, period_one.score, period_two.score,period_three.score

from period_one

LEFT JOIN period_two
ON period_one.subject_id = period_two.subject_id
AND period_one.student_id = period_two.student_id

LEFT JOIN period_three 
on period_one.subject_id = period_three.subject_id
AND period_one.student_id = period_three.student_id

WHERE period_one.student_id = 10      

Проблема с приведенным выше кодом заключается в том, что искомый идентификатор студента находится не в самой первой таблице (periodOne), к которому применяется левое соединение, и возвращает запрос null, даже если записи этого студента находятся в других таблицах (periodTwo). и periodThree). Я смотрю на проблему ( https://www.w3schools.com/sql/sql_join_left.asp ) и убедился, что это не лучший способ сделать что-то.

Я ПОТОМ ИЗМЕНИЛ НЕКОТОРЫЕ ИЗМЕНЕНИЯ

Итак, я обновил свой запрос, чтобы он выглядел так ( Query2 ):

SELECT students.student_id, period_one.score, period_one.subject_id, 
period_two.score, period_two.subject_id, period_three.score, 
period_three.subject_id
from students

LEFT JOIN period_one
ON students.student_id = period_one.student_id

LEFT JOIN period_two
ON students.student_id = period_two.student_id

LEFT JOIN period_three 
ON students.student_id = period_three.student_id

ГДЕ student.student_id = 3 ИЛИ period_one.student_id = 3 ИЛИ period_two.student_id = 3 ИЛИ period_three.student_id = 3

Это прекрасно работает, так как таблица студентов - это основная таблица, на которую ссылаются все таблицы периодов . При этом, если идентификатор студента находится не в таблице period_one и period_two, а в period_there, для этой таблицы возвращаются studentId, subjectId и score.

Затем всплывают другие проблемы

До того, как я обновил свой код, я немного отображал записи так, как хотел, но не получал / не извлекал записи желаемым способом. Именно это побудило меня изменить свой запрос, потому что я заметил, что это была проблема.

Теперь, основываясь на моем первом запросе ( Query1 ), я выбирал subject_id из различных таблиц в операторе select. Когда я отображаю записи, я передал возвращаемый объект subject_id из запроса в функцию, которая получает имя субъекта для этого идентификатора. Вот как я отображал свои результаты:

enter image description here

Это работает, если идентификатор студента находится в таблице, назначенной предложению from, в противном случае он ничего не возвращает. Вот почему я меняю свой код.

Но теперь, когда я изменил свой код на ( Query2 ), я не могу отобразить идентификатор субъекта и его имя, поскольку его нет в таблице учеников. Вот краткое описание того, как я отображаю свои записи: https://gist.github.com/nathansiafa / e9d22791800d4ba3a00e2b98de52baec

Есть ли способ, которым я могу заставить его работать лучше? Буду признателен за предложения, а также обратная связь. Спасибо!

1
Nathan Siafa 24 Апр 2017 в 17:04

2 ответа

Лучший ответ

Кажется, что вы немного обдумываете это с технической / программной точки зрения и не сосредотачиваетесь на семантическом значении данных, которые вы хотите иметь.

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

Таким образом, шаг 1 должен был бы выбрать данные, которые мы хотим - предметы и оценки для них:

SELECT s.subject_id, s.subject_name, p1.score period_1_score, p2.score period_2_score, p3.score period_3_score 
FROM subject s
LEFT JOIN period_one p1 ON p1.subject_id = s.subject_id 
    AND p1.student_id = 10
LEFT JOIN period_two p2 ON p2.subject_id = s.subject_id 
    AND p2.student_id = 10
LEFT JOIN period_three p3 ON p3.subject_id = s.subject_id 
    AND p3.student_id = 10
ORDER BY s.subject_name;

Это даст вам данные таблицы, которые вы хотите - в первую очередь предметы, а затем баллы, где они существуют.

Теперь, если вы настаиваете на загрузке данных об ученике в одном запросе (для этого я бы посоветовал создать отдельный запрос SELECT * FROM student WHERE student_id=10), вы можете присоединиться к нему слева вверху:

SELECT s.subject_id, s.subject_name, p1.score period_1_score, p2.score period_2_score, p3.score period_3_score, st.name student_name
FROM subject s
LEFT JOIN period_one p1 ON p1.subject_id = s.subject_id 
    AND p1.student_id = 10
LEFT JOIN period_two p2 ON p2.subject_id = s.subject_id 
    AND p2.student_id = 10
LEFT JOIN period_three p3 ON p3.subject_id = s.subject_id 
    AND p3.student_id = 10
LEFT JOIN student st ON st.student_id = 10
ORDER BY s.subject_name;
0
mkilmanas 24 Апр 2017 в 14:29

Для меня проблема в том, что данные не в нормальном виде, что вызывает у вас проблему. Поскольку предметы и оценки в основном имеют одинаковую структуру без обозначений периодов, я сначала объединяю все три таблицы вместе и создаю столбец «Период» в результате.

SELECT X.*, 1 as Period from Period_one X
UNION ALL 
SELECT Y.*, 2 as Period FROM PERIOD_TWO Y
UNION ALL
SELECT Z.*, 3 as Period FROM PERIOD_THREE Z

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

SELECT Student_ID
     , max(Case when Period = 1 then B.Subject_ID end) as Period_one_Subject
     , max(case when Period = 1 then B.Score end) as Period_one_Score 
     , max(Case when Period = 2 then B.Subject_ID) end as Period_Two_Subject
     , max(case when Period = 2 then B.Score end as Period_two_Score 
     , max(Case when Period = 3 then B.Subject_ID end) as Period_Three_Subject
     , max(case when Period = 3 then B.Score end) as Period_Three_Score 
FROM STUDENTS S
LEFT JOIN (SELECT Y.*, 1 as Period from Period_one X
           UNION ALL 
           SELECT X.*, 2 as Period FROM PERIOD_TWO Y
           UNION ALL
           SELECT Z.*, 3 as Period FROM PERIOD_THREE Z) B
 on S.Student_ID = B.Student_ID
GROUP BY Student_ID

Мы используем максимальное и групповое по студентам, чтобы «Pivot» данные, позволяющие нам показать как балл и предмет.

Если нам нужно фактическое имя субъекта, просто присоединить его к вашей таблице тем на основе ключа subject_ID.

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

0
xQbert 24 Апр 2017 в 14:19