通过查看成员的最新状态获取成员列表
Get list of members by looking at the their latest status
我有一个复杂的案例,我正在将其简化为 MVCE 示例。假设我们有一个 MySQL table 包含一堆俱乐部和许多学生。每个学生可以加入多个社团,也可以随时离开。
出于 MVCE 目的,让我们考虑下面的 table:
/* Table: membership */
Club Student Date Status
ABC Alice 1/1/2020 Joined
ABC Bob 1/1/2020 Joined
ABC Charlie 1/2/2020 Joined
XYZ Charlie 1/2/2020 Joined
ABC Alice 1/6/2020 Left
ABC Alice 1/12/2020 Joined
ABC Charlie 1/12/2020 Left
XYZ Alice 1/12/2020 Joined
我使用什么语句来查找 1/9/2020
俱乐部 ABC 中的所有学生?答案应该是 Charlie
和 Bob
。如果我们将日期更改为 1/12/2020
,答案应该是 Alice
和 Bob
,因为那天 Alice
加入并且 Charlie
离开。
这是我尝试过的方法,但 return 我想要的是:
SELECT Student
FROM membership
WHERE
Club = "ABC" AND
(SELECT MAX(Date) WHERE Status="Joined" ) > (select MAX(Date) WHERE Status="Left") ;
此外,以上考虑了当前的成员资格。我怎样才能让它成为特定日期的会员?
试试这个:
SELECT
Student
FROM
Membership
WHERE
Club = "ABC" AND Date = "2020-1-12";
如果您能将“加入”的记录与相应的“左”或null
(如果有none)相匹配,那么您就大功告成了。我要应用的逻辑是对应于“加入”的记录必须由相同的“俱乐部”和“学生”记录。日期有点棘手,因为有可能出现这种情况:
Club Student Date Status
ABC Alice 2020-01-01 Joined
ABC Alice 2020-01-02 Left
ABC Alice 2020-01-03 Joined
ABC Alice 2020-01-04 Left
ABC Alice 2020-01-05 Joined
可以通过日期大于“加入”但最早的“左”记录找到对应的记录。
由于“加入”并不总是有相应的记录,如上例中最后一个“加入”有 none,我使用了使用 LEFT JOIN
:
SELECT joined.club,
joined.student,
joined.date AS joindate,
left_.date AS leavedate
FROM Membership AS joined
LEFT JOIN Membership AS left_ ON joined.club = left_.club -- must match
AND joined.student = left_.student -- must match
AND left_.Status = 'Left' -- match to "Left"
-- Only the minimum date of the dates
-- ..greater or equal to "Joined" date
AND left_.date = (SELECT min(date)
FROM Membership min
WHERE 1 = 1
AND min.club = left_.club
AND min.student = left_.student
AND min.date >= joined.date
AND min.Status = 'Left')
WHERE joined.Status = 'Joined'
导致:
club
student
joindate
leavedate
ABC
Alice
2020-01-01
2020-01-06
ABC
Bob
2020-01-01
null
ABC
Charlie
2020-01-02
2020-01-12
XYZ
Charlie
2020-01-02
null
ABC
Alice
2020-01-12
null
XYZ
Alice
2020-01-12
null
要在某个日期获得会员资格,您只需添加:
AND joined.date <= '2020-01-06'
AND coalesce(left_.date,'9999-12-31') > '2020-01-06'
或
AND '2020-01-12' BETWEEN joined.date
AND coalesce(date_add(left_.date,interval -1 day),'9999-12-31')
由于 BETWEEN
包含在内,所以我减去一天。我已经使用 coalesce
来确保当没有对应的“左”时,比较的日期始终是最大日期。
但是,将以上具有相同“俱乐部”、“学生”和“加入”日期的记录分组等同于:
SELECT joined.club,
joined.student,
joined.date AS joindate,
min(left_.date) AS leavedate
FROM Membership AS joined
LEFT JOIN Membership AS left_ ON joined.club = left_.club
AND joined.student = left_.student
AND left_.status = 'Left'
AND left_.date >= joined.date
WHERE joined.status = 'Joined'
GROUP BY joined.club, joined.student, joined.date
添加日期将改为使用 HAVING
,因为它在结果上:
HAVING '2020-01-12' BETWEEN joined
AND coalesce(date_add(`left`,interval -1 day),'9999-12-31')
我建议您使用 DATETIME
或 TIMESTAMP
而不是 DATE
,因为您将遇到这种情况:
Club Student Date Status
B52 Peter 2020-10-03 Joined
B52 Peter 2020-10-03 Left
B52 Peter 2020-10-03 Joined
或
Club Student Date Status
B52 Benny 2020-10-01 Joined
B52 Benny 2020-10-03 Left
B52 Benny 2020-10-03 Joined
“左派”大于或等于“加入派”中的任何一个,彼得和本尼在 3 日似乎都不是成员,因此在以后的任何日期也都不是成员。
如果您为您的 table 并检查“左”记录是否总是晚于“加入”记录,而不是检查 left_.date >= joined.date
.
使“离开”日期严格大于“加入”日期似乎可以解决问题,但实际上没有人能够在与他们相同的日期离开加入了。
另请注意,使用 GROUP BY
的查询将消除 Peter 重复的“加入”日期。
我有一个复杂的案例,我正在将其简化为 MVCE 示例。假设我们有一个 MySQL table 包含一堆俱乐部和许多学生。每个学生可以加入多个社团,也可以随时离开。
出于 MVCE 目的,让我们考虑下面的 table:
/* Table: membership */
Club Student Date Status
ABC Alice 1/1/2020 Joined
ABC Bob 1/1/2020 Joined
ABC Charlie 1/2/2020 Joined
XYZ Charlie 1/2/2020 Joined
ABC Alice 1/6/2020 Left
ABC Alice 1/12/2020 Joined
ABC Charlie 1/12/2020 Left
XYZ Alice 1/12/2020 Joined
我使用什么语句来查找 1/9/2020
俱乐部 ABC 中的所有学生?答案应该是 Charlie
和 Bob
。如果我们将日期更改为 1/12/2020
,答案应该是 Alice
和 Bob
,因为那天 Alice
加入并且 Charlie
离开。
这是我尝试过的方法,但 return 我想要的是:
SELECT Student
FROM membership
WHERE
Club = "ABC" AND
(SELECT MAX(Date) WHERE Status="Joined" ) > (select MAX(Date) WHERE Status="Left") ;
此外,以上考虑了当前的成员资格。我怎样才能让它成为特定日期的会员?
试试这个:
SELECT
Student
FROM
Membership
WHERE
Club = "ABC" AND Date = "2020-1-12";
如果您能将“加入”的记录与相应的“左”或null
(如果有none)相匹配,那么您就大功告成了。我要应用的逻辑是对应于“加入”的记录必须由相同的“俱乐部”和“学生”记录。日期有点棘手,因为有可能出现这种情况:
Club Student Date Status
ABC Alice 2020-01-01 Joined
ABC Alice 2020-01-02 Left
ABC Alice 2020-01-03 Joined
ABC Alice 2020-01-04 Left
ABC Alice 2020-01-05 Joined
可以通过日期大于“加入”但最早的“左”记录找到对应的记录。
由于“加入”并不总是有相应的记录,如上例中最后一个“加入”有 none,我使用了使用 LEFT JOIN
:
SELECT joined.club,
joined.student,
joined.date AS joindate,
left_.date AS leavedate
FROM Membership AS joined
LEFT JOIN Membership AS left_ ON joined.club = left_.club -- must match
AND joined.student = left_.student -- must match
AND left_.Status = 'Left' -- match to "Left"
-- Only the minimum date of the dates
-- ..greater or equal to "Joined" date
AND left_.date = (SELECT min(date)
FROM Membership min
WHERE 1 = 1
AND min.club = left_.club
AND min.student = left_.student
AND min.date >= joined.date
AND min.Status = 'Left')
WHERE joined.Status = 'Joined'
导致:
club | student | joindate | leavedate |
---|---|---|---|
ABC | Alice | 2020-01-01 | 2020-01-06 |
ABC | Bob | 2020-01-01 | null |
ABC | Charlie | 2020-01-02 | 2020-01-12 |
XYZ | Charlie | 2020-01-02 | null |
ABC | Alice | 2020-01-12 | null |
XYZ | Alice | 2020-01-12 | null |
要在某个日期获得会员资格,您只需添加:
AND joined.date <= '2020-01-06'
AND coalesce(left_.date,'9999-12-31') > '2020-01-06'
或
AND '2020-01-12' BETWEEN joined.date
AND coalesce(date_add(left_.date,interval -1 day),'9999-12-31')
由于 BETWEEN
包含在内,所以我减去一天。我已经使用 coalesce
来确保当没有对应的“左”时,比较的日期始终是最大日期。
但是,将以上具有相同“俱乐部”、“学生”和“加入”日期的记录分组等同于:
SELECT joined.club,
joined.student,
joined.date AS joindate,
min(left_.date) AS leavedate
FROM Membership AS joined
LEFT JOIN Membership AS left_ ON joined.club = left_.club
AND joined.student = left_.student
AND left_.status = 'Left'
AND left_.date >= joined.date
WHERE joined.status = 'Joined'
GROUP BY joined.club, joined.student, joined.date
添加日期将改为使用 HAVING
,因为它在结果上:
HAVING '2020-01-12' BETWEEN joined
AND coalesce(date_add(`left`,interval -1 day),'9999-12-31')
我建议您使用 DATETIME
或 TIMESTAMP
而不是 DATE
,因为您将遇到这种情况:
Club Student Date Status
B52 Peter 2020-10-03 Joined
B52 Peter 2020-10-03 Left
B52 Peter 2020-10-03 Joined
或
Club Student Date Status
B52 Benny 2020-10-01 Joined
B52 Benny 2020-10-03 Left
B52 Benny 2020-10-03 Joined
“左派”大于或等于“加入派”中的任何一个,彼得和本尼在 3 日似乎都不是成员,因此在以后的任何日期也都不是成员。
如果您为您的 table 并检查“左”记录是否总是晚于“加入”记录,而不是检查 left_.date >= joined.date
.
使“离开”日期严格大于“加入”日期似乎可以解决问题,但实际上没有人能够在与他们相同的日期离开加入了。
另请注意,使用 GROUP BY
的查询将消除 Peter 重复的“加入”日期。