Как написать SQL ниже, чтобы отобразить все детали

Я не знаю, правильно ли я делаю метод ниже при использовании sql, но здесь это идет.

Я хочу отобразить все детали экзамена (подробности экзамена (также называемые сессией), вопросы на экзамене, ответы, штрафы, изображения, видео и т. Д.) Но способ, которым я пытаюсь это сделать, - это один большой запрос, но он не работает, как нет строки отображаются

Ниже показано, что я хочу показать для одного экзамена (и только одного экзамена):

  • Детали экзамена
  • Все вопросы на экзамене
  • Все ответы на каждый вопрос и оценки каждого ответа стоит
  • Штраф (посмотреть, если включен или нет)
  • Наказания за неправильные ответы
  • Изображения в вопросе
  • Видео в вопросах
  • Аудио в вопросах
  • Детали модуля
  • Ученик

Ниже покажите поля, которые каждый раздел требует от базы данных:

  • Детали экзамена

    SessionId, SessionName, SessionDuration, TotalMarks, SessionWeight

  • Все вопросы на экзамене

    QuestionId, QuestionNo, QuestionContent, NoofAnswers, QuestionMarks, OptionId, OptionType, ReplyId, ReplyType

  • Все ответы на каждый вопрос и оценки каждого ответа стоит

AnswerId, Answer, AnswerMarks

  • Штраф (посмотреть, если включен или нет)

PenaltyEnabled

  • Штрафные ответы

PenaltyAnswerId, PenaltyAnswer, PenaltyMarks

  • Изображения в вопросе

ImageId, ImageFile

  • Видео в вопросах

VideoId VideoFile

  • Аудио в вопросах

AudioId, AudioFile

  • Детали модуля

ModuleId, ModuleNo, ModuleName

  • Ученик

StudentId

У меня вопрос, как должен быть написан код SQL, чтобы все эти данные отображались? Мне нужен только один большой запрос или много маленьких запросов? Моя попытка в нижней части вопроса, но ниже таблицы базы данных, которые показывают детали, касающиеся одного экзамена и все его детали.

ТАБЛИЦЫ:

Ученик

StudentId (PK)  StudentForename  StudentSurname
1              James            Parker

Student_Session

SessionId (FK)  StudentId (FK)
1              1

сессия

SessionId (PK) SessionName  SessionDuration  TotalMarks  SessionWeight  ModuleId (FK)
1             AAA          01:00:00        30         20            1

модуль

ModuleId (PK)  ModuleNo  ModuleName
1              CHI2513   ICT

Вопрос

SessionId FK) QuestionId (PK)  QuestionNo QuestionContent NoofAnswers QuestionMarks OptionId (FK) ReplyId (FK)
1             4                1           Question 1      1           5              1            1
1             5                2           Question 2      1           3              2            1
1             6                3           Question 3      2           6              2            2
1             7                4           Question 4      3           7              5            2
1             8                5           Question 5      1           9              5            1

Ответ:

AnswerId (PK) Answer  QuestionId (FK)
1              A       4
2              C       5
3              A       6
4              B       6
5              B       7
6              D       7
7              E       7
8              G       8

Индивидуальный ответ

IndividualId (PK)  AnswerId (FK) AnswerMarks  
1                    1              3       
2                    2              5       
3                    3              3       
4                    4              3       
5                    5              2       
6                    6              2       
7                    7              3       
8                    8              9       

неустойка

PenaltyId(PK) SessionId (FK)  PenaltyEnalbed
1             1               1

PenaltyMarks

PenaltyAnswerId (PK) PenaltyAnswer PenaltyMarks QuestionId (FK)
1                     B            1            4
2                     C            1            4
3                     A            1            5
4                     B            1            5
5                     D            1            5
6                     C            2            6
7                     D            2            6
8                     A            1            7
9                     C            1            7
10                    F            1            7
11                    G            1            7
12                    A            0            8
13                    B            0            8
14                    C            1            8
15                    D            1            8
16                    E            1            8
17                    F            0            8

Ответить

ReplyId (PK)  ReplyType
1               Single
2               Multiple

Option_Table

OptionId (PK)  OptionType
1               A-C        
2               A-D
3               A-E
4               A-F
5               A-G

Образ

ImageId (PK)  ImageFile
1              ImageFile/Tulips.png
2              ImageFile/Daisys.png

видео

VideoId (PK) VideoFile
1              VideoFile/Speech.png

аудио

AudioId (PK) AudioFile
1               AudioFile/Song.png

Image_Question

   ImageQuestionId (PK) ImageId (FK) SessionId (FK)  QuestionNo (FK)
   1                    1             1                2

Video_Question

VideoQuestionId (PK) VideoId (FK) SessionId (FK)  QuestionNo (FK)
1                      1            1                   4

Audio_Question

AudioQuestionId (PK) AudioId (FK) SessionId (FK)  QuestionNo (FK)
1                      1            1                  5

Ниже была моя неудачная попытка:

SELECT s.SessionId, 
       SessionName, 
       SessionDuration, 
       TotalMarks, 
       SessionWeight, 
       q.QuestionId, 
       q.QuestionNo, 
       QuestionContent, 
       QuestionMarks, 
       q.OptionId, 
       OptionType, 
       q.ReplyId, 
       ReplyType, 
       a.AnswerId, 
       Answer, 
       NoofAnswers, 
       AnswerMarks, 
       PenaltyEnabled, 
       PenaltyAnswerId, 
       PenaltyAnswer, 
       PenaltyMarks, 
       i.ImageId, 
       au.AudioId, 
       v.VideoId, 
       ImageFile, 
       AudioFile, 
       VideoFile, 
       s.ModuleId, 
       ModuleNo, 
       ModuleName, 
       ss.StudentId 
FROM   Student st 
       INNER JOIN Student_Session ss 
               ON st.StudentId = ss.StudentId 
       INNER JOIN Session s 
               ON ss.SessionId = s.SessionId 
       INNER JOIN Question q 
               ON s.SessionId = q.SessionId 
       INNER JOIN Answer a 
               ON q.QuestionId = a.AnswerId 
       INNER JOIN Individual_Answer ia 
               ON a.AnswerId = ia.AnswerId 
       LEFT JOIN Module m 
              ON s.ModuleId = m.ModuleId 
       LEFT JOIN Penalty p 
              ON q.SessionId = p.SessionId 
       LEFT JOIN Option_Table o 
              ON q.OptionId = o.OptionId 
       LEFT JOIN Reply r 
              ON q.ReplyId = r.ReplyId 
       LEFT JOIN Penalty_Marks pm 
              ON q.QuestionId = pm.QuestionId 
       LEFT JOIN Image_Question iq 
              ON q.QuestionId = iq.QuestionNo 
       INNER JOIN Image i 
               ON iq.ImageId = i.ImageId 
       LEFT JOIN Audio_Question aq 
              ON q.QuestionId = aq.QuestionNo 
       INNER JOIN Audio au 
               ON aq.AudioId = au.AudioId 
       LEFT JOIN Video_Question vq 
              ON q.QuestionId = vq.QuestionNo 
       INNER JOIN Video v 
               ON vq.VideoId = v.VideoId 
WHERE  s.SessionId = 1
ORDER  BY q.QuestionId 

ОБНОВИТЬ:

Сможет ли приведенный ниже код вставлять QuestionId в таблицу Image_Question после отправленных вопросов: (Это то, что я нашел в SO, но обновил до своего дизайна таблицы)

ImageQuestionToken
{
  ImageToken (PK auto)
  SessionId
}

Image{
   ImageId 
   ImageFile
}

Image_Question
{
  Image_QuestionId
  ImageId FK references Image(ImageId)
  QuestionId FK references Question(QuestionId)

}

Question
{
  QuestionId (PK Auto)
  QuestionNo
  QuestionContent
  ....
}

TempImage
{
  ImageToken FK references ImageQuestionToken(ImageToken)
  ImageFile
}

И логика такова:

  1. Пользователь запрашивает форму вопроса. Сервер устанавливает токен и включает в ответ пользователя.
  2. Пользователь загружает картинку, включая токен. Изображение хранится во временной таблице.
  3. Шаг 2 повторяется n раз.
  4. Если пользователь отправляет вопрос со значением токена, запись помещается в таблицу вопросов и присваивается идентификатор. Все изображения в таблице TempImage, имеющие общий токен, вставляются в таблицу изображений с теперь известным QuestionId. Затем запись ImageQuestionToken удаляется, а каскад удаляет временные изображения в TempImage.
  5. Если пользователь не отправит вопрос, файлы будут удалены, а запись в ImageQuestionToken удалена.

4 ответа

Решение

В этих таблицах есть проблема с вашими внешними ключами: Image_Question, Audio_Question и Video_Question.

Вы используете столбец QuestionNo, который не проиндексирован таблицей Question. Я бы предложил заменить столбцы на QuestionId и использовать их значения.

Image_Question

ImageQuestionId (PK) ImageId (FK) SessionId (FK)  QuestionNo(FK)
   1                    1             1                2

Video_Question

VideoQuestionId (PK) VideoId (FK) SessionId (FK)  QuestionNo(FK)
   1                      1            1               4

Audio_Question

AudioQuestionId (PK) AudioId (FK) SessionId (FK)  QuestionNo(FK)
   1                      1            1               5

и ваше заявление должно выглядеть так:

SELECT s.SessionId, 
       SessionName, 
       SessionDuration, 
       TotalMarks, 
       SessionWeight, 
       q.QuestionId, 
       q.QuestionNo, 
       QuestionContent, 
       QuestionMarks, 
       q.OptionId, 
       OptionType, 
       q.ReplyId, 
       ReplyType, 
       a.AnswerId, 
       Answer, 
       NoofAnswers, 
       AnswerMarks, 
       PenaltyEnabled, 
       PenaltyAnswerId, 
       PenaltyAnswer, 
       PenaltyMarks, 
       i.ImageId, 
       au.AudioId, 
       v.VideoId, 
       ImageFile, 
       AudioFile, 
       VideoFile, 
       s.ModuleId, 
       ModuleNo, 
       ModuleName, 
       ss.StudentId 
FROM   Student st 
       INNER JOIN Student_Session ss 
               ON st.StudentId = ss.StudentId 
       INNER JOIN Session s 
               ON ss.SessionId = s.SessionId 
       INNER JOIN Question q 
               ON s.SessionId = q.SessionId 
       INNER JOIN Answer a 
               ON q.QuestionId = a.AnswerId 
       INNER JOIN Individual_Answer ia 
               ON a.AnswerId = ia.AnswerId 
       LEFT JOIN Module m 
              ON s.ModuleId = m.ModuleId 
       LEFT JOIN Penalty p 
              ON q.SessionId = p.SessionId 
       LEFT JOIN Option_Table o 
              ON q.OptionId = o.OptionId 
       LEFT JOIN Reply r 
              ON q.ReplyId = r.ReplyId 
       LEFT JOIN Penalty_Marks pm 
              ON q.QuestionId = pm.QuestionId 
       LEFT JOIN Image_Question iq 
              ON q.QuestionNo= iq.QuestionNo
       LEFT JOIN Image i
               ON iq.ImageId = i.ImageId 
       LEFT JOIN Audio_Question aq 
              ON q.QuestionNo= aq.QuestionNo
       LEFT JOIN Audio au 
               ON aq.AudioId = au.AudioId 
       LEFT JOIN Video_Question vq 
              ON q.QuestionNo= vq.QuestionNo
       LEFT JOIN Video v 
               ON vq.VideoId = v.VideoId 
WHERE  s.SessionId = 1
ORDER  BY q.QuestionId

Обновление: вы можете использовать столбец QuestionNo, в конце концов, вы можете просто добавить индекс, чтобы вам не пришлось переделывать свои коды. хехехе

Я предлагаю вам добавить это:

ALTER TABLE `your_schema`.`Question` 
ADD INDEX `your_idx` (`QuestionNo` ASC);

и вместо них:

  LEFT JOIN Image_Question iq 
    ON q.QuestionId = iq.QuestionId -- from iq.QuestionNo
  LEFT JOIN Image i
    ON iq.ImageId = i.ImageId 
  LEFT JOIN Audio_Question aq 
    ON q.QuestionId = aq.QuestionId -- from aq.QuestionNo
  LEFT JOIN Audio au 
    ON aq.AudioId = au.AudioId 
  LEFT JOIN Video_Question vq 
    ON q.QuestionId = vq.QuestionId -- from vq.QuestionNo
  LEFT JOIN Video v 
    ON vq.VideoId = v.VideoId

Вы используете это:

  LEFT JOIN Image_Question iq 
    ON q.QuestionNo= iq.QuestionNo
  LEFT JOIN Image i
    ON iq.ImageId = i.ImageId 
  LEFT JOIN Audio_Question aq 
    ON q.QuestionNo= aq.QuestionNo
  LEFT JOIN Audio au 
    ON aq.AudioId = au.AudioId 
  LEFT JOIN Video_Question vq 
    ON q.QuestionNo= vq.QuestionNo
  LEFT JOIN Video v 
    ON vq.VideoId = v.VideoId

Пока я не на 100% уверен в том, какой именно результат вы хотите. На основе вашего существующего запроса проблема заключается в том, что вы используете INNER JOIN на некоторых из таблиц, когда вы должны использовать LEFT JOIN,

В вашем существующем запросе вы используете следующее:

LEFT JOIN Image_Question iq 
  ON q.QuestionId = iq.QuestionNo 
INNER JOIN Image i 
  ON iq.ImageId = i.ImageId 
LEFT JOIN Audio_Question aq 
  ON q.QuestionId = aq.QuestionNo 
INNER JOIN Audio au 
  ON aq.AudioId = au.AudioId 
LEFT JOIN Video_Question vq 
  ON q.QuestionId = vq.QuestionNo 
INNER JOIN Video v 
  ON vq.VideoId = v.VideoId 

Проблема в том, что INNER JOIN проверяет соответствие записей во всех полях, но у вас может не быть записи, существующей в image, audio или же video таблицы, так что ничего не возвращается.

Исходя из ваших данных ваш запрос должен быть похож на это:

select st.studentid,
  s.sessionid,
  s.sessionname,
  s.sessionduration,
  s.totalmarks,
  s.sessionweight,
  q.questionid,
  q.questionno,
  q.questioncontent,
  q.noofanswers,
  q.questionmarks,
  q.optionid,
  ot.optiontype,
  q.replyid,
  r.replytype,
  a.answerid,
  a.answer,
  ia.answermarks,
  p.penaltyenabled,
  pm.penaltyanswerid, 
  pm.penaltyanswer,
  pm.penaltymarks,
  i.imageid,
  i.imagefile,
  v.videoid,
  v.videofile,
  ad.audioid,
  ad.audiofile,
  m.moduleid,
  m.moduleno,
  m.modulename
from Student st 
inner join Student_Session ss
  on st.studentid = ss.studentid
inner join session s
  on ss.sessionid = s.sessionid
inner join question q
  on s.sessionid = q.sessionid
inner join answer a
  on q.questionid = a.questionid
inner join Individual_Answer ia
  on a.answerid = ia.answerid
left join Option_Table ot
  on q.optionid = ot.optionid
left join reply r
  on q.replyid = r.replyid
left join module m
  on s.moduleid = m.moduleid
left join Penalty p
  on s.sessionid = p.sessionid
left join penalty_marks pm
  on q.questionid = pm.questionid
left join image_question iq  -- note I am joining on both session and question
  on s.sessionid = iq.sessionid
  and q.questionid = iq.questionno
left join image i  -- this should be a left join not inner join
  on iq.imageid = i.imageid
left join video_question vq -- note I am joining on both session and question
  on s.sessionid = vq.sessionid
  and q.questionid = vq.questionno
left join video v  -- this should be a left join not inner join
  on vq.videoid = v.videoid
left join audio_question aq  -- note I am joining on both session and question
  on s.sessionid = aq.sessionid
  and q.questionid = aq.questionno
left join audio ad  -- this should be a left join not inner join
  on aq.audioid = ad.audioid
where  s.SessionId = 1
order by q.QuestionId 

Смотрите SQL Fiddle с демонстрацией.

Это возвращает все данные, которые вы запросили выше. Образец:

| STUDENTID | SESSIONID | SESSIONNAME | SESSIONDURATION | TOTALMARKS | SESSIONWEIGHT | QUESTIONID | QUESTIONNO | QUESTIONCONTENT | NOOFANSWERS | QUESTIONMARKS | OPTIONID | OPTIONTYPE | REPLYID | REPLYTYPE | ANSWERID | ANSWER | ANSWERMARKS | PENALTYENABLED | PENALTYANSWERID | PENALTYANSWER | PENALTYMARKS | IMAGEID | IMAGEFILE | VIDEOID |            VIDEOFILE | AUDIOID |          AUDIOFILE | MODULEID | MODULENO | MODULENAME |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|         1 |         1 |         AAA |        01:00:00 |         30 |            20 |          4 |          1 |      Question 1 |           1 |             5 |        1 |        A-C |       1 |    Single |        1 |      A |           3 |              1 |               1 |             B |            1 |  (null) |    (null) |       1 | VideoFile/Speech.png |  (null) |             (null) |        1 |  CHI2513 |        ICT |
|         1 |         1 |         AAA |        01:00:00 |         30 |            20 |          4 |          1 |      Question 1 |           1 |             5 |        1 |        A-C |       1 |    Single |        1 |      A |           3 |              1 |               2 |             C |            1 |  (null) |    (null) |       1 | VideoFile/Speech.png |  (null) |             (null) |        1 |  CHI2513 |        ICT |
|         1 |         1 |         AAA |        01:00:00 |         30 |            20 |          5 |          2 |      Question 2 |           1 |             3 |        2 |        A-D |       1 |    Single |        2 |      C |           5 |              1 |               3 |             A |            1 |  (null) |    (null) |  (null) |               (null) |       1 | AudioFile/Song.png |        1 |  CHI2513 |        ICT |
|         1 |         1 |         AAA |        01:00:00 |         30 |            20 |          5 |          2 |      Question 2 |           1 |             3 |        2 |        A-D |       1 |    Single |        2 |      C |           5 |              1 |               5 |             D |            1 |  (null) |    (null) |  (null) |               (null) |       1 | AudioFile/Song.png |        1 |  CHI2513 |        ICT |
|         1 |         1 |         AAA |        01:00:00 |         30 |            20 |          5 |          2 |      Question 2 |           1 |             3 |        2 |        A-D |       1 |    Single |        2 |      C |           5 |              1 |               4 |             B |            1 |  (null) |    (null) |  (null) |               (null) |       1 | AudioFile/Song.png |        1 |  CHI2513 |        ICT |

Ну, попробуйте это небольшими сменами: я имею в виду следующее:- Выполните запрос по частям, сначала удалите несколько объединений (удалите большинство из них), и добавьте их одно за другим, я делаю то же самое для своих огромных запросов, чтобы отслеживать, где является реальной проблемой, или какие условия делают основные различия для получения результирующих строк. просто идея. Ура!

И я думаю

 LEFT JOIN Image_Question iq 
              ON q.QuestionId = iq.QuestionNo 

даст вам нулевые значения

Поскольку q.QuestionId начинается с формы 4, а iq.QuestionNo равен 2

INNER JOIN Image i 
               ON iq.ImageId = i.ImageId 

И все значения в полях Iq, полученные из левых внешних объединений, равны нулю. Поэтому любое внутреннее объединение на них обязательно даст вам нулевые результаты.

Ключевая проблема: часто строки не возвращаются с использованием внутреннего соединения внешней объединенной таблицы

Я запросил, используя синтаксис Microsoft SQL. Надеюсь, поможет. Посмотрите мои предупреждения внизу и проигнорируйте оператор процедуры create, если хотите, вместо этого просто объявите и установите @SessionID равным 1 в верхней части.

create procedure GetStuff(
    @SessionID as integer
    ) as

declare @StudentID int -- you may need to use a different data type
select @StudentID = StudentID from Student_Session where SessionID = @SessionID

-- now we can at least remove the sessions table from the join list.

SELECT s.SessionId, 
       SessionName, 
       SessionDuration, 
       TotalMarks, 
       SessionWeight, 
       q.QuestionId, 
       q.QuestionNo, 
       QuestionContent, 
       QuestionMarks, 
       q.OptionId, 
       OptionType, 
       q.ReplyId, 
       ReplyType, 
       a.AnswerId, 
       Answer, 
       NoofAnswers, 
       AnswerMarks, 
       PenaltyEnabled, 
       PenaltyAnswerId, 
       PenaltyAnswer, 
       PenaltyMarks, 
       i.ImageId, 
       au.AudioId, 
       v.VideoId, 
       ImageFile, 
       AudioFile, 
       VideoFile, 
       s.ModuleId, 
       ModuleNo, 
       ModuleName, 
       ss.StudentId 
FROM   Student st 
       INNER JOIN Student_Session ss 
               ON st.StudentId = ss.StudentId 
       INNER JOIN Session s 
               ON ss.SessionId = s.SessionId 
       INNER JOIN Question q 
               ON s.SessionId = q.SessionId 
       INNER JOIN Answer a 
               ON q.QuestionId = a.AnswerId 
       INNER JOIN Individual_Answer ia 
               ON a.AnswerId = ia.AnswerId 
       LEFT outer JOIN Module m 
              ON s.ModuleId = m.ModuleId 
       LEFT outer JOIN Penalty p 
              ON q.SessionId = p.SessionId 
       LEFT outer JOIN Option_Table o 
              ON q.OptionId = o.OptionId 
       LEFT outer JOIN Reply r
              ON q.ReplyId = r.ReplyId 
       LEFT outer JOIN Penalty_Marks pm 
              ON q.QuestionId = pm.QuestionId 
        -- you can't inner join off of an outer joined table, or you'll get no rows for the entire query. I've nested the query, which is bad practice but... practical for getting this monster of a query working.
       LEFT outer JOIN (select c3.ImageID, c3.ImageFile from Image_Question as a1 inner join Images as b1 on a1.QuestionNo = b1.QuestionNo inner join Image as c1 on a1.ImageID = c1.ImageID)
               ON q.QuestionID = iq.QuestionID
        -- you can't inner join off of an outer joined table, or you'll get no rows for the entire query. I've nested the query, which is bad practice but... practical for getting this monster of a query working.
       LEFT outer JOIN (select b2.AudioID, b2.AudioFile from Audio_Question as a2 inner join Audio as b2 on a2.AudioID = b2.AudioID) as aq
              ON q.QuestionId = aq.QuestionNo 
        -- you can't inner join off of an outer joined table, or you'll get no rows for the entire query. I've nested the query, which is bad practice but... practical for getting this monster of a query working.
        left outer join (select b3.VideoID, b3.VideoFile from Video_Question as a3 inner join Video as b3 on a3.QuestionID = b3.QuestionID) as vq 
WHERE  
    st.StudentID = @StudentID
    and 
    s.SessionId = @SessionID
ORDER  BY q.QuestionId 
go

Предупреждения: вы действительно хотите разбить это на отдельные кусочки для отображения в вашем клиентском приложении. Например, для экзаменов и экзаменов требуется подробное отображение мастера / детализации, в противном случае вам придется подавлять повторяющиеся значения в выводе, отображаемом для пользователя. Например, ваш вывод будет выглядеть так, концептуально:

<Exam Detail Fields>    <Exam Detail Fields>
first one unique        What is the color of your DOG?
repeat          What is the color of your CAT?
repeat          What is the color of your CAR?
repeat          What is the color of your HAT?

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

Другие вопросы по тегам