mysql_leftjoin.txt
    sampdb.zip
    我们有一个记录学生的student表,有一个记录已发生考试或测验事件的grade_event表,还有一个记录每位学生的每次考试成绩的score表。现在查找缺考的学生。

    1. # create student table for grade-keeping project
    2. DROP TABLE IF EXISTS student;
    3. #@ _CREATE_TABLE_
    4. CREATE TABLE student
    5. (
    6. name VARCHAR(20) NOT NULL,
    7. sex ENUM('F','M') NOT NULL,
    8. student_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    9. PRIMARY KEY (student_id)
    10. ) ENGINE=InnoDB;
    11. #@ _CREATE_TABLE_
    12. # create grade event table for grade-keeping project
    13. DROP TABLE IF EXISTS grade_event;
    14. #@ _CREATE_TABLE_
    15. CREATE TABLE grade_event
    16. (
    17. date DATE NOT NULL,
    18. category ENUM('T','Q') NOT NULL,
    19. event_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    20. PRIMARY KEY (event_id)
    21. ) ENGINE=InnoDB;
    22. #@ _CREATE_TABLE_
    23. # create score table for grade-keeping project
    24. # The PRIMARY KEY comprises two columns to prevent any combination
    25. # of event_id/student_id from appearing more than once.
    26. DROP TABLE IF EXISTS score;
    27. #@ _CREATE_TABLE_
    28. CREATE TABLE score
    29. (
    30. student_id INT UNSIGNED NOT NULL,
    31. event_id INT UNSIGNED NOT NULL,
    32. score INT NOT NULL,
    33. PRIMARY KEY (event_id, student_id),
    34. INDEX (student_id),
    35. FOREIGN KEY (event_id) REFERENCES grade_event (event_id),
    36. FOREIGN KEY (student_id) REFERENCES student (student_id)
    37. ) ENGINE=InnoDB;
    38. #@ _CREATE_TABLE_
    39. ##insert 语句见附件


    要解决的问题是:确定哪些学生在某次考试或测验当天缺考了。也就是说 我们要查找学生和事件的组合没有在score表里出现过。
    第一步:确定“学生+事件”的组合

    from student inner join grade_event
    

    第二步:“学生+事件”组合结果集,与score表一起执行left join操作

    from student inner join grade_event
        LEFT JOIN   score
            ON  student.student_id=score.student_id
            AND grade_event.event_id =score.event_id
    

    第三步:将缺失的列筛选出来

    where score.score is null
    

    最终SQL为:

    SELECT
        student.name,
        student.student_id,
        grade_event.date,
        grade_event.event_id,
        grade_event.category
    FROM
        student
    INNER JOIN
        grade_event
    LEFT JOIN
        score
    ON
        student.student_id=score.student_id
    AND grade_event.event_id =score.event_id
    WHERE
        score.score IS NULL
    ORDER BY
        student.student_id,
        grade_event.event_id;