MySQL: 从最近的组中获取最旧的记录
MySQL: get oldest record from most recent group
抱歉标题令人困惑,但这是解释它的最佳方式。这不是一个常见的 "most recent from group" 问题,我在网上找不到任何类似的问题。
我有一个状态 table 可以跟踪人们在不同工作地点所做的事情。它包含 link 人、状态和位置的记录。
ID, start_date, person_ID, location_ID, status
1, 2014-10-12, 1, 1, job a
2, 2014-10-13, 2, 2, job b
3, 2014-10-15, 1, 3, job c
4, 2014-10-21, 1, 3, job d
5, 2014-10-22, 2, 4, job a
6, 2014-10-26, 2, 2, job d
我需要能够确定每个人在当前站点停留了多长时间 - 我希望得到这样的结果:
person_ID, location_ID, since
1, 3, 2014-10-15
2, 2, 2014-10-26
通过加入 max(start_date),获取当前工作的开始时间相对容易,但我需要从最近位置完成的工作中获取 min(start_date)。
我一直在尝试将 min(start_date) 加入与当前位置匹配的记录中(来自最近的记录),并且在我找到一个人(比如人 2)之前效果很好谁多次访问当前位置...您可以在我想要的结果中看到我想要 10-26 日期,而不是 10-13,这是他们第一次访问该站点。
我需要一些方法来匹配给定人员的工作记录,然后迭代返回直到位置不匹配。我想必须有一些方法可以通过一些 sub-queries 和一些巧妙的连接来做到这一点,但我还没有找到它,所以我会很感激一些帮助。
我认为最简单的方法是使用变量来跟踪您需要的信息:
select person_id, location_id, min(start_date) as since
from (select s.*,
(@rn := if(@p <> person_id, if(@p:=person_id, 1, 1),
if(@l = location_id, @rn,
if(@l:=location_d, @rn + 1, @rn + 1)
)
)
) as location_counter
from status s cross join
(select @p := 0, @l := 0, @rn := 0) vars
order by person_id, start_date desc
) s
where location_counter = 1
group by person_id, location_id;
变量的奇怪逻辑是(试图)枚举每个人的位置。它应该仅在位置更改时递增 @rn
并为新人将值重置为 1
。
其实很简单
SELECT g.person_ID,
(SELECT l.location_ID
FROM status l
WHERE l.person_ID = g.person_ID
AND l.start_date = MAX(g.start_date)) AS location,
MAX(g.start_date) AS since
FROM status g
GROUP BY g.person_ID
这使用 person_ID 上的分组,并使用 SELECT 作为位置列表达式。
唯一的问题是你的意思是不是 MIN i.o。 MAX 在你的例子中你产生了最年轻的日期,而不是最老的。
如果我正确理解您的问题,您可以使用 EXISTS
消除除每个人最近的位置之外的所有位置,并从结果行中获取最短日期。
SELECT person_id, location_id, MIN(start_date) since
FROM status s
WHERE NOT EXISTS (
SELECT 1 FROM status
WHERE s.person_id = person_id
AND s.location_id <> location_id
AND s.start_date < start_date)
GROUP BY person_id
基本上,它消除了同一个人最近访问过另一个位置的所有位置和时间。例如;
1, 2014-10-12, 1, 1, job a
...被淘汰,因为人 1 最近访问了位置 3,而;
3, 2014-10-15, 1, 3, job c
...保留,因为同一个人最近才访问过同一地点。
然后它只选择每个人最近最少的时间。由于只保留最后一个位置的行,因此它将是距离最近位置最近的时间。
抱歉标题令人困惑,但这是解释它的最佳方式。这不是一个常见的 "most recent from group" 问题,我在网上找不到任何类似的问题。
我有一个状态 table 可以跟踪人们在不同工作地点所做的事情。它包含 link 人、状态和位置的记录。
ID, start_date, person_ID, location_ID, status
1, 2014-10-12, 1, 1, job a
2, 2014-10-13, 2, 2, job b
3, 2014-10-15, 1, 3, job c
4, 2014-10-21, 1, 3, job d
5, 2014-10-22, 2, 4, job a
6, 2014-10-26, 2, 2, job d
我需要能够确定每个人在当前站点停留了多长时间 - 我希望得到这样的结果:
person_ID, location_ID, since
1, 3, 2014-10-15
2, 2, 2014-10-26
通过加入 max(start_date),获取当前工作的开始时间相对容易,但我需要从最近位置完成的工作中获取 min(start_date)。
我一直在尝试将 min(start_date) 加入与当前位置匹配的记录中(来自最近的记录),并且在我找到一个人(比如人 2)之前效果很好谁多次访问当前位置...您可以在我想要的结果中看到我想要 10-26 日期,而不是 10-13,这是他们第一次访问该站点。
我需要一些方法来匹配给定人员的工作记录,然后迭代返回直到位置不匹配。我想必须有一些方法可以通过一些 sub-queries 和一些巧妙的连接来做到这一点,但我还没有找到它,所以我会很感激一些帮助。
我认为最简单的方法是使用变量来跟踪您需要的信息:
select person_id, location_id, min(start_date) as since
from (select s.*,
(@rn := if(@p <> person_id, if(@p:=person_id, 1, 1),
if(@l = location_id, @rn,
if(@l:=location_d, @rn + 1, @rn + 1)
)
)
) as location_counter
from status s cross join
(select @p := 0, @l := 0, @rn := 0) vars
order by person_id, start_date desc
) s
where location_counter = 1
group by person_id, location_id;
变量的奇怪逻辑是(试图)枚举每个人的位置。它应该仅在位置更改时递增 @rn
并为新人将值重置为 1
。
其实很简单
SELECT g.person_ID,
(SELECT l.location_ID
FROM status l
WHERE l.person_ID = g.person_ID
AND l.start_date = MAX(g.start_date)) AS location,
MAX(g.start_date) AS since
FROM status g
GROUP BY g.person_ID
这使用 person_ID 上的分组,并使用 SELECT 作为位置列表达式。
唯一的问题是你的意思是不是 MIN i.o。 MAX 在你的例子中你产生了最年轻的日期,而不是最老的。
如果我正确理解您的问题,您可以使用 EXISTS
消除除每个人最近的位置之外的所有位置,并从结果行中获取最短日期。
SELECT person_id, location_id, MIN(start_date) since
FROM status s
WHERE NOT EXISTS (
SELECT 1 FROM status
WHERE s.person_id = person_id
AND s.location_id <> location_id
AND s.start_date < start_date)
GROUP BY person_id
基本上,它消除了同一个人最近访问过另一个位置的所有位置和时间。例如;
1, 2014-10-12, 1, 1, job a
...被淘汰,因为人 1 最近访问了位置 3,而;
3, 2014-10-15, 1, 3, job c
...保留,因为同一个人最近才访问过同一地点。
然后它只选择每个人最近最少的时间。由于只保留最后一个位置的行,因此它将是距离最近位置最近的时间。