MySQL:从最近的组中获取最早的记录

时间:2015-01-29 04:24:07

标签: mysql records

对于令人困惑的标题感到抱歉,但这是解释它的最佳方式。这不是通常的“最近出现的群体”问题,而且我无法在网上找到类似的内容。

我有一个状态表,可以跟踪人们在各个工作地点的行为。它包含链接人员,状态和位置的记录。

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这是他们第一次来到这个网站。

我需要一些方法来匹配给定人员的工作记录,然后迭代回来直到该位置不匹配。我想要有一些方法可以用一些子查询和一些聪明的连接来做到这一点,但我还没有找到它,所以我会感激一些帮助。

3 个答案:

答案 0 :(得分:1)

我认为最简单的方法是使用变量来跟踪所需的信息:

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值。

答案 1 :(得分:1)

如果我理解你的要求是正确的,你可以使用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

An SQLfiddle to test with

基本上,它消除了同一个人最近访问过其他位置的所有位置和时间。例如;

1,  2014-10-12, 1,         1,           job a

...因为人1最近访问了位置3而被淘汰,而;

3,  2014-10-15, 1,         3,           job c
由于同一个人最近才访问过同一地点,因此保留了...

然后只选择每个人最近的时间。由于只保留了最后一个位置的行,因此它将是最近位置的最近时间。

答案 2 :(得分:-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会产生最年轻的日期,而不是最早的日期。