MySQL - 返回一个表中与另一个(间接链接)表中的最小日期对应的行

时间:2014-01-28 21:40:39

标签: mysql join min multi-table

表学期:

semesterID  startDate
1           2013-01-01
2           2013-03-01
3           2013-06-01

表类:

classID  class_title  semesterID
1        Math         1
2        Science      1
3        Math         2
4        Science      2
5        Math         3
6        Science      3

表人:

personID  firstName  lastName
1         John       Jones
2         Steve      Smith

表class_person:

classID  personID
1        1
2        1
5        1
6        1
3        2
4        2
5        2
6        2

我需要获得所有人的列表,第一个学期他们参加了一个班级(学期最早的startDate)。

firstName,  lastName, semesterID, startDate
John        Jones     1           2013-01-01
Steve       Smith     2           2013-03-01

我花了好几个小时试图解决这个问题。这是我得到的最接近的(虽然它根本不是很接近!):

SELECT p.firstName, p.lastName, MIN(s.startDate) AS min_startDate
FROM semesters s
INNER JOIN classes c ON s.semesterID = c.semesterID
INNER JOIN class_person cp ON cp.classID = c.classID
INNER JOIN persons p ON p.personID = cp.personID
GROUP BY cs.personID
ORDER BY min_startDate, p.lastName, p.firstName

任何帮助都会受到大力赞赏。谢谢。

1 个答案:

答案 0 :(得分:1)

你最终可能会使用类似下面的怪物(fiddle):

select persons.firstName, persons.lastName,
       semesters.semesterID, semesters.startDate
from persons, semesters,
(select p.personID,
 (select semesters.semesterID
  from semesters, classes, class_person
  where semesters.semesterID = classes.semesterID
    and classes.classID = class_person.classID
    and class_person.personID = p.personID
  order by semesters.startDate
  limit 1) as semesterID
 from (select distinct personID from class_person) as p
) as ps
where persons.personID = ps.personID
  and semesters.semesterID = ps.semesterID

子查询p标识所有人。对于每个,ps将包含一行。简单地复制personID,其semesterID由子查询计算,子查询按日期对学期进行排序,但返回ID。最外面的查询然后重新添加日期。

如果你真的不需要semesterID,你可以避免使用一层。如果您的学期有序,即他们的ID与startDates的顺序相同,那么您可以简单地使用单个查询,就像您自己的一样,并返回min(semesterID)min(startDate)

总的来说,这个问题让我想起了很多我自己的问题,Select one value from a group based on order from other columns。答案表明这里也可能适用。特别是,有一些使用用户变量的方法,我仍然感到不舒服,但这将使整个混乱很多更容易,并且似乎工作得很好。因此,调整this answer,您会收到类似这样的查询(fiddle):

SELECT p.firstName, p.lastName, s2.semesterID, s2.startDate
FROM persons p
INNER JOIN (
 SELECT @rowNum:=IF(@personID=cp.personID,@rowNum+1,1) rowNum,
        @personId:=cp.personID personID,
        s.semesterID, s.startDate
 FROM (SELECT @personID:=NULL,@rowNum:=0) dummy
 INNER JOIN semesters s
 INNER JOIN classes c ON s.semesterID = c.semesterID
 INNER JOIN class_person cp ON cp.classID = c.classID
 ORDER BY cp.personID, s.startDate
) s2 ON p.personID = s2.personID
WHERE s2.rowNum = 1

我会将其他答案作为练习。