I'm a high school teacher new to php|mySQL and I am trying to develop a query to display test scores from my students. The challenge is to show the scores on a given test and to show NULL if a score has not been posted. I am trying to make two steps into a single query:
The 'tests' table with records for each assessment contains these columns:
test_id
assessment_id
username
score
maxScore
stopTime
The 'users' table with records for each student contains these columns:
user_id
schoolId
username
first_name
last_name
section
Desired Result:
username | last_name | first_name | schoolId | assessment_id | score | maxScore
------------------------------------------------------------------------------------
jadams1 | Adams | Joe | 111111 | 23 | 9 | 12
sbenson1 | Benson | Sally | 222222 | 23 | 10 | 12
csmith2 | Smith | Charlie | 555555 | NULL | NULL | NULL (hasn't taken quiz yet)
dthomp1 | Thompson | David | 666666 | 23 | 9 | 12
So far I have tried a number of things. The first was a basic LEFT JOIN. This generates one row for each student, but since I specify a value for "tests.assessment_id", it does not display rows for students who haven't taken the quiz yet. I want it to display the quiz results if they exist, and a row for the student containing NULL score values if they haven't taken the quiz.
SELECT
users.last_name,
users.first_name,
tests.score,
tests.maxScore
FROM users
LEFT JOIN tests
ON tests.username = users.username
WHERE tests.assessment_id = '23'
AND users.section = 'S432-01'
The above generates:
username | last_name | first_name | schoolId | assessment_id | score | maxScore
------------------------------------------------------------------------------
jadams1 | Adams | Joe | 111111 | 23 | 9 | 12
sbenson1 | Benson | Sally | 222222 | 23 | 10 | 12
dthomp1 | Thompson | David | 666666 | 23 | 9 | 12
The following is a more recent iteration. It generates a NULL row for practice quizzes (with no assessment_id assigned) as well as a row for the real thing. In the final report, it is important to create only one row for each student, but not to miss any students:
SELECT DISTINCT
users.username,
users.last_name,
users.first_name,
users.schoolId,
if(tests.assessment_id ='23','23','') AS assessment,
if(tests.assessment_id ='23',tests.score,'') AS score,
if(tests.assessment_id ='23',tests.maxScore,'') AS maxScore
FROM `users`
LEFT JOIN tests
ON tests.username = users.username
WHERE users.section = 'S432-01'
AND (tests.assessment_id = '23'
OR tests.assessment_id IS NULL)
ORDER BY users.last_name,users.first_name,tests.assessment_id
The above generates:
username | last_name | first_name | schoolId | assessment_id | score | maxScore
------------------------------------------------------------------------------------
jadams1 | Adams | Joe | 111111 | NULL | NULL | NULL
jadams1 | Adams | Joe | 111111 | 23 | 9 | 12
sbenson1 | Benson | Sally | 222222 | NULL | NULL | NULL
sbenson1 | Benson | Sally | 222222 | 23 | 10 | 12
csmith2 | Smith | Charlie | 555555 | NULL | NULL. | NULL (hasn't taken quiz yet)
dthomp1 | Thompson | David | 666666 | NULL | NULL. | NULL
dthomp1 | Thompson | David | 666666 | 23 | 9 | 12
Any ideas how to make this work in a single query? I think I'm having performance problems, so I would like to keep things as simple as possible.
Thanks for your help! -Chris
This will work,
SELECT users.last_name,
users.first_name,
tests.score,
tests.maxScore
FROM users
LEFT JOIN tests
ON tests.username = users.username AND
tests.assessment_id = '23'
WHERE users.section = 'S432-01'
The reason why you are not getting all records from users
table is because you have filtered assessment_id
which is equal to 23
which drops all the null
values ( students that have not taken the assessment has null value on this column ). In order to get all values, move the tests.assessment_id='23'
on the ON
clause.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.