简体   繁体   中英

mySQL SELECT using LEFT JOIN, returning value or NULL WHERE column is specified in right table

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:

  1. Create a list of students in a particular course based on submitted test results.
  2. Display each student's score on that test, or, if a score doesn't exist because they haven't taken a test, display their name and NULL next to it.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM