简体   繁体   中英

LEFT JOIN of only the latest row from a many-to-one

Been banging my head against the wall and cannot solve this :\\

SELECT
  `people`.*,
  `students`.*,
  `student_class_relationships`.*,
  `geo_checkin_on_campus`.`datetime_created` as checkin_time
FROM `student_class_relationships`
  LEFT OUTER JOIN `students`
    ON `student_class_relationships`.`student` = `students`.`id`
  LEFT OUTER JOIN `people`
    ON `students`.`student` = `people`.`id`
  LEFT OUTER JOIN `geo_checkin_on_campus`
    ON `students`.`id` = (
      SELECT MIN(`geo_checkin_on_campus`.`student`)
      FROM `geo_checkin_on_campus`
      WHERE `geo_checkin_on_campus`.`student` = `students`.`id`
    )
 WHERE `class` = 56

The expected result is many rows that have only one entry per students.id .

Here is my schema

It is not the best query from performance perspective,

but just to fix your query here is my attempt:

SELECT
  `people`.*,
  `students`.*,
  `student_class_relationships`.*,
  geoCheckinOnCampus.datetimeCreated as checkin_time
FROM `student_class_relationships`
  LEFT JOIN `students`
    ON `student_class_relationships`.`student` = `students`.`id`
  LEFT JOIN `people`
    ON `students`.`student` = `people`.`id`
  LEFT JOIN 
    (
      SELECT 
        student,
        MAX(datetime_created) datetimeCreated
      FROM `geo_checkin_on_campus`
      GROUP BY `student`
    ) geoCheckinOnCampus
  ON `students`.`id` = geoCheckinOnCampus.`student`
 WHERE `class` = 56

Note According to @xQbert answer I would really change MIN to MAX function if you are looking for the latest datetime.

If i assume you want the most recent checkin (and not the earliest created date) for each student in go_checkin_on_Campus then...

SELECT
  `people`.*,
  `students`.*,
  `student_class_relationships`.*,
  B.`datetime_Updated` as checkin_time
FROM `student_class_relationships`
  LEFT OUTER JOIN `students`
    ON `student_class_relationships`.`student` = `students`.`id`
  LEFT OUTER JOIN `people`
    ON `students`.`student` = `people`.`id`
  LEFT OUTER JOIN (
      SELECT max(datetime_updated), student
      FROM `geo_checkin_on_campus`
      group by student
) B
    ON `students`.`id` = B.Student
 WHERE `class` = 56

NOTE: This is a probable answer. I will edit / modify this according to comments from OP.

This basically does nothing. This is as good as just joining on the student id

LEFT OUTER JOIN `geo_checkin_on_campus`
    ON `students`.`id` = (
      SELECT MIN(`geo_checkin_on_campus`.`student`)
      FROM `geo_checkin_on_campus`
      WHERE `geo_checkin_on_campus`.`student` = `students`.`id`
    )

If you want the min (or earliest) datetime_created use something like

LEFT OUTER JOIN (
      SELECT `geo_checkin_on_campus`.`student` student,
              MIN(`geo_checkin_on_campus`.`datetime_created`) dt
      FROM   `geo_checkin_on_campus`
      WHERE  `geo_checkin_on_campus`.`student` = `students`.`id`
      GROUP BY `geo_checkin_on_campus`.`student`
    ) t
    ON `students`.`id` = t.student

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