MySQL one to many get the no matching record - mysql

Im not good at explaining things so please bear with me.. Here's what I'm trying to do. I want to get the result of rows with no matching record to the table(tbl_personnel_documents) if I'm looking for the documents with a "YES" priority and based on their position.
Here's the structure of the table for employee:
tbl_personnel_info
id name position_id
1 John 1
2 Sharyn 2
3 Stacie 4
4 Kevin 3
5 Cristine 3
Table for Position:
tbl_position
id position_name
1 IT Manager
2 Accounting Staff
3 IT Staff
4 H.R Manager
5 Admin Staff
Table for personnel documents:
tbl_personnel_documents
id personnel_id document_id document_num
1 1 3 111-222-333-444
2 1 4 AB-CC-DD
3 2 1 CC-BB-DD
4 4 2 1-2-3-4-5
5 3 4 C1-D2-X1-D2-G3
Table for documents name
tbl_documents
id document_name priority
1 Passport YES
2 ROPC NO
3 US Visa YES
4 AUS Visa YES
Table for document priority based on their position
tbl_priority_docs_per_position
id position_id document_id
1 1 1
2 1 3
3 1 4
In this case, John's position is an IT Manager which have no record of passport in the table(tbl_personnel_documents). And since the document Passport is a priority document for IT Manager but it is missing, it must display the result.
Im currently stuck in here.. I can't get the desired result.. Here's my code:
SELECT td.document_name
FROM tbl_personnel_info AS tpi
LEFT JOIN tbl_position AS tp
ON tp.id = tpi.position_id
LEFT JOIN tbl_personnel_documents AS tpd
ON tpi.id = tpd.personnel_id
LEFT JOIN tbl_documents AS td
ON td.id = tpd.document_id
LEFT JOIN tbl_priority_docs_per_position AS tpriority
ON tpriority.position_id = tpi.position_id AND tpriority.document_id = tpd.document_id
WHERE td.priority = 'YES'
AND tpi.id = 1 -- John's ID
AND tpriority.document_id IS NULL
Please help.. Thank you
Update: I manage to partially get the result with this code:
SELECT td.document_name
FROM tbl_personnel_info AS tpi
LEFT JOIN tbl_position AS tp
ON tp.id = tpi.position_id
LEFT JOIN tbl_personnel_documents AS tpd
ON tpi.id = tpd.personnel_id
LEFT JOIN tbl_documents AS td
ON td.priority = 'YES'
LEFT JOIN tbl_priority_docs_per_position AS tpriority
ON tpriority.position_id = tpi.position_id AND tpriority.document_id = tpd.document_id
WHERE tpi.id = 1 -- John's ID
AND tpriority.document_id IS NULL
GROUP BY td.id
Now my problem is whenever I change the position_id of tbl_priority_docs_per_position, I still get the same result.

When you use a left join you must be very careful how you reference that table in the where clause or you might override the join. Here however I believe it is the sequence of joins:
SELECT
*
FROM tbl_personnel_info AS tpi
INNER JOIN tbl_position AS tp ON tp.id = tpi.position_id
INNER JOIN tbl_priority_docs_per_position AS tpriority ON tpriority.position_id = tpi.position_id
LEFT JOIN tbl_personnel_documents AS tpd ON tpi.id = tpd.personnel_id
AND tpriority.document_id = tpd.document_id
LEFT JOIN tbl_documents AS td ON td.id = tpd.document_id
WHERE tpi.id = 1 -- John's ID
AND td.priority IS NULL
;
Demo
| id | name | position_id | id | position_name | id | position_id | document_id | id | personnel_id | document_id | document_num | id | document_name | priority |
|----|------|-------------|----|---------------|----|-------------|-------------|--------|--------------|-------------|--------------|--------|---------------|----------|
| 1 | John | 1 | 1 | IT Manager | 1 | 1 | 1 | (null) | (null) | (null) | (null) | (null) | (null) | (null) |

Related

MySQL Query JOIN 3 tables

Looking to join 3 tables, but having trouble on the last one.
members
ID | name
---------
1 | John
2 | Jane
3 | Jack
member_points (can have multiple transactions between members)
ID | date | id_from | id_to
---------------------------
1 | 8/8 | 1 | 2
2 | 8/8 | 1 | 2
3 | 8/8 | 3 | 2
member_ratings (one member can only rate another member, one time)
ID | id_from | id_to | rating
-----------------------------
1 | 2 | 1 | 5
Each member may rate each member only once, and can only rate the member they received a point from, based on the member_points table.
My current query achieves this, however I'm having difficulty introducing the 3rd table, that will include the rating accoringly.
Here is what I have so far:
$sql = '
SELECT *,
m.id AS id,
c1.id AS id_from,
c1.name AS name_from,
c2.id AS id_to,
c2.name AS name_to
FROM member_points AS m
JOIN members AS c1 ON m.id_from = c1.id
JOIN members AS c2 ON m.id_to = c2.id
and m.id_to='.$_SESSION["userid"].'
GROUP BY name_from';
My goal is join the 3rd table so I can call the associated rating.
ID | name_from | name_to | rating
----------------------------------
1 | 2 | 1 | 5
2 | 2 | 3 | pending
#Andrew you need to use a LEFT JOIN to join in the member_ratings table like this:
$sql = '
SELECT *,
m.id AS id,
c1.id AS id_from,
c1.name AS name_from,
c2.id AS id_to,
c2.name AS name_to,
IF(mr.rating IS NULL, 'pending', mr.rating) AS rating
FROM member_points AS m
JOIN members AS c1 ON m.id_from = c1.id
JOIN members AS c2 ON m.id_to = c2.id
and m.id_to='.$_SESSION["userid"].'
LEFT JOIN member_ratings AS mr ON mr.id_from = c1.id
AND mr.id_to = c2.id
GROUP BY name_from';
please let me know if this isn't what you need and I'll try to help you further.

IF using inner join MySql?

How do I build a joint to select either table
Table jobs
Id | name | salary | company | type
1 | php | 17.850 | 5 | 1
2 | mysql | 4.500 | 89 | 2
2 | nodejs | 7.500 | 89 | 1
Table Company
Id | name | Area | status
1 | Facebook| Developer| 1
2 | Google | Manager | 1
Table Candidate
Id | name | City | phone
1 | Alan Kout | Nevada | 1 555 6666
2 | Wagner Mom | L.A. | 1 444 8965
My query mysql, inner join candidate or company
If type == 1 in table jobs INNER JOIN ON table company
If type == 2 in table jobs INNER JOIN ON table candidate
Example
SELECT * FROM table_jobs
IF(table_jobs.type == 1, INNER JOIN table_company, INNER JOIN table_candidate)
This is possible?
You can achieve this using a LEFT JOIN instead of an INNER JOIN:
SELECT *
FROM table_jobs tj
LEFT JOIN table_company tco ON tj.type = 1 AND tco.id = tj.id
LEFT JOIN table_candidate tca ON tj.type = 2 AND tca.id = tj.id
This will join to table_company where the type is 1, and table_candidate where the type is 2.
You can then SELECT whichever columns are needed from each table as appropriate.
Use left join and coalesce():
SELECT tj.*,
coalesce(co.name, ca.name) as name,
. . .
FROM table_jobs tj LEFT JOIN
table_company co
ON co.id = tj.id and tj.type = 1 LEFT JOIN
table_candidate ca
ON ca.id = tj.id and tj.type = 2;
If you want both joins in one result you can use the UNION operator
SELECT *
FROM table_jobs INNER JOIN table_company
WHERE table_jobs.type=1
UNION
SELECT *
FROM table_jobs INNER JOIN table_candidate
WHERE table_jobs.type=2

Mysql : Join 4 table problem with the result

I have 4 table and join with all then i want show data like here :
pr_id |nama | jumlah_liker | id_user
1 |Milk | 5 | 1
2 |Choco| 0 | 1
Review Table produk
pr_id | nama
1 | Milk
2 | Choco
3 | Salad
Review Table liker
id_produk | id_user
1 | 1
1 | 1
1 | 1
1 | 3
1 | 2
Review Table featured_ukm
id | id_produk
1 | 1
2 | 2
But i got sql record
id_produk | nama | jumlah_liker | id_user
1 | milk | 1 | 1 //problem row i dont get count all record id_produk
2 | choco | 0 | 1
SELECT produk.*, COUNT(liker.id_produk), liker.id_user
FROM produk
left join liker ON liker.id_produk = produk.pr_id AND liker.id_user = 1
INNER JOIN featured_ukm ON featured_ukm.id_produk = produk.pr_id
GROUP BY featured_ukm.id_produk
Edit: My suggestions are first, I actually put what will produce your exact requested results at the bottom
It appears that you're trying to show how many likes each of the "Featured Product" has.
It isn't entirely clear what you're trying to do with the user id, or what its purpose in the result set is; here is a query to show how many likes each "Featured Product" has:
SELECT
produk.*,
(SELECT IFNULL(COUNT(*), 0)
FROM liker WHERE liker.id_produk = produk.pr_id)
FROM featured_ukm F
INNER JOIN produk ON produk.pr_id = F.id_produk
Here is a query to show how many likes each product by each user
SELECT DISTINCT
P.*,
(SELECT IFNULL(COUNT(*), 0) FROM liker WHERE liker.id_user = L.id_user),
IFNULL(L.id_user, 0)
FROM produk P
LEFT JOIN liker L ON L.id_produk = P.pr_id
and if you want to just see the items that ONE user liked, add:
WHERE L.id_user = 1
to the end of it.
Here is a query to show how many likes each Featured Product has for each user id:
SELECT DISTINCT
P.*,
(SELECT IFNULL(COUNT(*), 0) FROM liker WHERE liker.id_user = L.id_user),
IFNULL(L.id_user, 0)
FROM produk P
LEFT JOIN liker L ON L.id_produk = P.pr_id
INNER JOIN featured_ukm F on F.id_produk = P.pr_id
To get the exact result set that it would appear that you're looking for (in your example), you will need to reference a user table in your query. I assume you have one because you're referencing user ids. For the purpose of this example, I'm creating the below user table.
id | name
----------------
1 | user_one
2 | user_two
3 | user_three
With this table, the following query will give exactly what it appears you're looking for:
SELECT P.*, (SELECT IFNULL(COUNT(*), 0) FROM liker WHERE liker.id_produk =
F.id_produk), user.id
FROM user
CROSS JOIN featured_ukm F
LEFT JOIN produk P ON F.id_produk = P.pr_id
WHERE user.id = 1
But play around with some of my other example queries. They may be more helpful.

How to join 5 tables with IF conditions

I want to join 5 tables through book_id. I tried:
SELECT booked_room_info . * , booking_info . * , hotel_info.name as
hotelname,hotel_info.address as hoteladdress,hotel_info.contact as
hotelcontact , personal_info . *,room_registration.room_name as
roomname,room_registration.price as roomprice,room_registration.price as
roomprice,room_registration.description as
roomdescription,room_registration.image as roomimage
FROM booked_room_info
JOIN booking_info ON booking_info.booking_id = booked_room_info.booking_id
JOIN hotel_info ON hotel_info.id = booking_info.hotel_id
JOIN personal_info ON personal_info.booking_id = booked_room_info.booking_id
JOIN room_registration ON room_registration.hotel_id = booking_info.hotel_id
WHERE booked_room_info.booking_id= 1
But if i have 2 booking on booking_id = 1 but it fetched 10 result. I think I should make a if condition like. If (booked.room_type && book_info.hotel_id) is same then only fetch rows from room_registration but how can I aacomplish it.
booked_room_info
------
id | booking_id | room_type | check_in | check_out
1 | 1 | delux | 2015/1/2 | 2015/1/5
booking_info
---------
id | booking_id | hotel_id | user_id
1 | 1 | 2 | 1
hotel_info
----------
id | name | address | user_id
2 |palm hotel | newyork | 1
personal_info
-------------
id |full_name | address | nationality | booking_id
1 | sushil stha | new york | smth | 1
room_registration
-----------------
id | room_name | price | image | hotel_id | user_id
1 | delux | 1000 |room.jpg | 2 | 1
There is an error in your last join:
JOIN room_registration ON room_registration.hotel_id = booking_info.hotel_id
You are joining these tables using hotel_id column. There are probably 5 rows in room_registration table with hotel_id=2. So after joining you receive 2*5=10 rows instead of expected 2.
So you should join with this table in different way.
If you want to join every row with exacly one row from room_registration table then you have to specify more precise join condition.
To join room_registration table properly you may add room_registration_id column to booking_info table. Then you can join using:
JOIN room_registration ON room_registration.id = booking_info.room_registration_id
Use INNER JOIN's, removed the duplicate field.
SELECT
bri.*,
bi.*,
hi.name AS hotelname, hi.address as hoteladdress, hi.contact AS hotelcontact,
pi.*,
rr.room_name AS roomname, rr.price AS roomprice, rr.description AS roomdescription, rr.image AS roomimage
FROM booked_room_info bri
INNER JOIN booking_info bi ON bri.booking_id = bi.booking_id
INNER JOIN hotel_info hi ON bi.hotel_id = hi.id
INNER JOIN personal_info pi ON bri.booking_id = pi.booking_id
INNER JOIN room_registration rr ON bi.hotel_id = rr.hotel_id
WHERE bri.booking_id = 1

How to write SQL below in order to display all details

I don't know if I am doing the below method correctly when using sql but here it goes.
I want to display all exam details (exams details (Also know as Session), questions in exam, answers, penalty, images, videos etc) But the way I am trying to do it is one big query but it is not working as no rows are being displayed.
Below are what I want to display for one exam (and only one exam):
Exam Details
All questions in Exam
All Answers to each question and marks each answer worth
Penalty (see if enabled or not)
Penalty marks for incorrect answers
Images in question
Videos in questions
Audio in questions
Module Details
Student
Below show the fields each section above require from database:
Exam Details
SessionId, SessionName, SessionDuration, TotalMarks, SessionWeight
All questions in Exam
QuestionId, QuestionNo, QuestionContent, NoofAnswers, QuestionMarks, OptionId, OptionType, ReplyId, ReplyType
All Answers to each question and marks each answer worth
AnswerId, Answer, AnswerMarks
Penalty (see if enabled or not)
PenaltyEnabled
Penalty answers
PenaltyAnswerId, PenaltyAnswer, PenaltyMarks
Images in question
ImageId, ImageFile
Videos in questions
VideoId VideoFile
Audio in questions
AudioId, AudioFile
Module Details
ModuleId, ModuleNo, ModuleName
Student
StudentId
My question is how should the SQL code be written in order for all these data to be shown? Do I just need one big query or a lot of little queries? My attempt is at bottom of question but below is the database tables which shows details dealing with one exam and all its details.
TABLES:
Student
StudentId (PK) StudentForename StudentSurname
1 James Parker
Student_Session
SessionId (FK) StudentId (FK)
1 1
Session
SessionId (PK) SessionName SessionDuration TotalMarks SessionWeight ModuleId (FK)
1 AAA 01:00:00 30 20 1
Module
ModuleId (PK) ModuleNo ModuleName
1 CHI2513 ICT
Question
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
Answer:
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
Individual Answer
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
Penalty
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
Reply
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
Image
ImageId (PK) ImageFile
1 ImageFile/Tulips.png
2 ImageFile/Daisys.png
Video
VideoId (PK) VideoFile
1 VideoFile/Speech.png
Audio
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
Below was my failed attempt:
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
UPDATE:
Will the code below be able to insert QuestionId into Image_Question Table after questions submitted: (This is something I found on SO but updated to my table design)
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
}
And the logic like so:
User requests question form. Server sets token and includes in response to user.
User uploads picture including token. Image is stored in temporary table.
Step 2 repeated n times.
If user submits question with token value, an entry is placed in the questions table and an id is assigned. All images in the TempImage table that share the token get inserted to the image table with the now known QuestionId. The ImageQuestionToken entry is then deleted and cascade deletes the temp images in TempImage.
Else user doesn't submit question then files are deleted and ImageQuestionToken entry deleted.
While I am not 100% sure of the exact result that you want. Based on your existing query the issue is that you are using INNER JOIN on some of the tables when you should be using LEFT JOIN.
In your existing query you are using the following:
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
The problem is that the INNER JOIN is checking for matching records on all fields but you might not have a record that exists in the image, audio or video tables so it is not returning anything.
Based on your details your query should be similar to this:
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
See SQL Fiddle with Demo.
This is returning all of the data that you have requested above. Sample:
| 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 |
There's a problem with your foreign keys in these tables: Image_Question, Audio_Question, and Video_Question.
You are using the column QuestionNo which is not indexed by the table Question.
I would suggest replacing the columns as QuestionId instead and used their values.
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
and your statement should look like this:
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
update:
You can use the column QuestionNo afterall, you could just add index so you don't have to overhaul your codes. hehehe
i suggest you add this:
ALTER TABLE `your_schema`.`Question`
ADD INDEX `your_idx` (`QuestionNo` ASC);
and instead of these:
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
you use these:
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
The key problem: often, no rows will be returned using an inner join off of an outer joined table
I have subqueried, using microsoft SQL syntax. Hope it helps. See my warnings at the bottom, and ignore the create procedure statement if you like and instead just declare and set the #SessionID to 1 at the top.
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
Warnings:
You will really want to break this down to seperate peices for displaying in your client application. For instance, you need a master/detail display for Exams and ExamDetails, otherwise you would have to suppress repeating values in the output shown to the user.
For instance, your output would look like this, conceptually:
<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?
Note the repetitive values on the left that you would have to suppress.
Well , Try it in small shifts : what I mean is:- Execute the query part by part
remove some joins at first (remove most of them ),and add them one by one ,I do the same for my huge queries to track where is the actual problem, or which conditions are making the main differences for getting the resulted rows. just an Idea. Cheers!
And i think
LEFT JOIN Image_Question iq
ON q.QuestionId = iq.QuestionNo
will give you null values
As q.QuestionId starts form 4 and iq.QuestionNo is 2
INNER JOIN Image i
ON iq.ImageId = i.ImageId
And all the values in Iq fields resulted from Left outer joins are null.So any Inner Join on them is Sure to give you null results.