MySQL LEFT OUTER JOIN虚拟表

时间:2012-11-13 16:45:29

标签: mysql left-join

我正在处理一个非常复杂的查询,让我试着向你解释一下。这是我在MySQL数据库中的表格:

学生表

--- `students` ---
student_id    first_name    last_name    current_status    status_change_date
------------  ------------  -----------  ----------------  --------------------
1             John          Doe          Active            NULL
2             Jane          Doe          Retread           2012-02-01

students_have_courses表

--- `students_have_courses` ---
students_student_id    courses_course_id    s_date      e_date      int_date
---------------------  -------------------  ----------  ----------  -----------
1                      1                    2012-01-01  2012-01-04  2012-01-05
1                      2                    2012-01-05  NULL        NULL
2                      1                    2012-01-10  2012-01-11  NULL

students_have_optional_courses表

--- `students_have_optional_courses` ---
students_student_id    optional_courses_opcourse_id    s_date      e_date
---------------------  ------------------------------  ----------  ----------
1                      1                               2012-01-02  2012-01-03
1                      1                               2012-01-06  NULL
1                      5                               2012-01-07  NULL

到目前为止,这是我的查询

SELECT 
  `students_and_courses`.student_id,
  `students_and_courses`.first_name,
  `students_and_courses`.last_name,
  `students_and_courses`.courses_course_id,
  `students_and_courses`.s_date,
  `students_and_courses`.e_date,
  `students_and_courses`.int_date,
  `students_have_optional_courses`.optional_courses_opcourse_id,
  `students_have_optional_courses`.s_date,
  `students_have_optional_courses`.e_date
FROM (
  SELECT
    `c_s_a_s`.student_id,
    `c_s_a_s`.first_name,
    `c_s_a_s`.last_name,
    `c_s_a_s`.courses_course_id,
    `c_s_a_s`.s_date,
    `c_s_a_s`.e_date,
    `c_s_a_s`.int_date
 FROM (
   SELECT
      `students`.student_id,
      `students`.first_name,
      `students`.last_name,
      `students_have_courses`.courses_course_id,
      `students_have_courses`.s_date,
      `students_have_courses`.e_date,
      `students_have_courses`.int_date
    FROM
      `students`
      LEFT OUTER JOIN `students_have_courses`
        ON (
          `students_have_courses`.`students_student_id` = `students`.`student_id` AND     (( 
          `students_have_courses`.`s_date` >= `students`.`status_change_date` AND
          `students`.current_status = 'Retread' ) OR
          `students`.current_status = 'Active')
        )
      WHERE
        `students`.current_status = 'Active' OR
        `students`.current_status = 'Retread'
  ) `c_s_a_s`
  ORDER BY
    `c_s_a_s`.`courses_course_id` DESC
) `students_and_courses`
LEFT OUTER JOIN `students_have_optional_courses`
  ON (
    `students_have_optional_courses`.students_student_id =     `students_and_courses`.student_id AND
    `students_have_optional_courses`.s_date >= `students_and_courses`.s_date AND 
    `students_have_optional_courses`.e_date IS NULL
  )
GROUP BY
 `students_and_courses`.student_id;

我想要返回的是所有Active或Retread学生的student_id,first_name和last_name,然后LEFT JOIN最高的course_id,s_date,e_date和int_date,用于s_date自status_change_date以来的那些学生状态是'翻新'。然后LEFT JOIN学生_have_optional_courses表格中最高的optional_courses_opcourse_id,s_date和e_date,其中students_have_optional_courses.s_date大于或等于students_have_courses.s_date和students_have_optional_courses.e_date IS NULL

以下是返回的内容:

student_id    first_name    last_name    courses_course_id    s_date      e_date      int_date      optional_courses_opcourse_id    s_date_1    e_date_1
------------  ------------  -----------  -------------------  ----------  ----------  ------------  ------------------------------  ----------  ----------
1             John          Doe          2                    2012-01-05  NULL        NULL          1                               2012-01-06  NULL
2             Jane          Doe          NULL                 NULL        NULL        NULL          NULL                            NULL        NULL

以下是我想要归还的内容:

student_id    first_name    last_name    courses_course_id    s_date      e_date      int_date      optional_courses_opcourse_id    s_date_1    e_date_1
------------  ------------  -----------  -------------------  ----------  ----------  ------------  ------------------------------  ----------  ----------
1             John          Doe          2                    2012-01-05  NULL        NULL          5                               2012-01-07  NULL
2             Jane          Doe          NULL                 NULL        NULL        NULL          NULL                            NULL        NULL

除了一件事,一切都在起作用,无论我如何形成查询,我都无法获得最高的学生_have_optional_courses.optional_courses_opcourse_id

抱歉,我写完这篇文章之后,我自己就解决了这个问题,我认为这有助于我思考解决方案。

以下是解决方案查询:

    SELECT 
      `students_and_courses`.student_id,
      `students_and_courses`.first_name,
      `students_and_courses`.last_name,
      `students_and_courses`.courses_course_id,
      `students_and_courses`.s_date,
      `students_and_courses`.e_date,
      `students_and_courses`.int_date,
      `students_optional_courses`.optional_courses_opcourse_id,
      `students_optional_courses`.s_date,
      `students_optional_courses`.e_date
    FROM (
      SELECT
        `c_s_a_s`.student_id,
        `c_s_a_s`.first_name,
        `c_s_a_s`.last_name,
        `c_s_a_s`.courses_course_id,
        `c_s_a_s`.s_date,
        `c_s_a_s`.e_date,
        `c_s_a_s`.int_date
      FROM (
        SELECT
          `students`.student_id,
          `students`.first_name,
          `students`.last_name,
          `students_have_courses`.courses_course_id,
          `students_have_courses`.s_date,
          `students_have_courses`.e_date,
          `students_have_courses`.int_date
        FROM
          `students`
          LEFT OUTER JOIN `students_have_courses`
            ON (
              `students_have_courses`.`students_student_id` = `students`.`student_id` AND (( 
              `students_have_courses`.`s_date` >= `students`.`status_change_date` AND
              `students`.current_status = 'Retread' ) OR
              `students`.current_status = 'Active')
            )
          WHERE
            `students`.current_status = 'Active' OR
            `students`.current_status = 'Retread'
      ) `c_s_a_s`
      ORDER BY
        `c_s_a_s`.`courses_course_id` DESC
    ) `students_and_courses`
    LEFT OUTER JOIN (
      SELECT
        *
      FROM
        `students_have_optional_courses`
      ORDER BY
        `students_have_optional_courses`.optional_courses_opcourse_id DESC
    ) `students_optional_courses`
      ON (
        `students_optional_courses`.students_student_id = `students_and_courses`.student_id AND
        `students_optional_courses`.s_date >= `students_and_courses`.s_date AND 
        `students_optional_courses`.e_date IS NULL
      )
    GROUP BY
     `students_and_courses`.student_id;

1 个答案:

答案 0 :(得分:2)

以下是我自己调试时发现的答案:

    SELECT 
      `students_and_courses`.student_id,
      `students_and_courses`.first_name,
      `students_and_courses`.last_name,
      `students_and_courses`.courses_course_id,
      `students_and_courses`.s_date,
      `students_and_courses`.e_date,
      `students_and_courses`.int_date,
      `students_optional_courses`.optional_courses_opcourse_id,
      `students_optional_courses`.s_date,
      `students_optional_courses`.e_date
    FROM (
      SELECT
        `c_s_a_s`.student_id,
        `c_s_a_s`.first_name,
        `c_s_a_s`.last_name,
        `c_s_a_s`.courses_course_id,
        `c_s_a_s`.s_date,
        `c_s_a_s`.e_date,
        `c_s_a_s`.int_date
      FROM (
        SELECT
          `students`.student_id,
          `students`.first_name,
          `students`.last_name,
          `students_have_courses`.courses_course_id,
          `students_have_courses`.s_date,
          `students_have_courses`.e_date,
          `students_have_courses`.int_date
        FROM
          `students`
          LEFT OUTER JOIN `students_have_courses`
            ON (
              `students_have_courses`.`students_student_id` = `students`.`student_id` AND (( 
              `students_have_courses`.`s_date` >= `students`.`status_change_date` AND
              `students`.current_status = 'Retread' ) OR
              `students`.current_status = 'Active')
            )
          WHERE
            `students`.current_status = 'Active' OR
            `students`.current_status = 'Retread'
      ) `c_s_a_s`
      ORDER BY
        `c_s_a_s`.`courses_course_id` DESC
    ) `students_and_courses`
    LEFT OUTER JOIN (
      SELECT
        *
      FROM
        `students_have_optional_courses`
      ORDER BY
        `students_have_optional_courses`.optional_courses_opcourse_id DESC
    ) `students_optional_courses`
      ON (
        `students_optional_courses`.students_student_id = `students_and_courses`.student_id AND
        `students_optional_courses`.s_date >= `students_and_courses`.s_date AND 
        `students_optional_courses`.e_date IS NULL
      )
    GROUP BY
     `students_and_courses`.student_id;

我需要在LEFT JOINING之前选择并订购students_have_optional_courses表。我希望这有助于任何其他人寻找这样的答案。