如何让我的GROUP BY获取特定列的最后一行(按日期)的值?

时间:2016-09-10 14:30:32

标签: mysql sql group-by

我有一个GROUP BY子句的查询。此查询需要员工" checkin" records表中的时间,如果dn字段 1 ,则该员工在办公室,但如果 2 ,然后他/她离开了。

所以我想把records.dn放在GROUP BY子句中。这导致每个员工的重复条目(我在一个表中一个接一个地得到他们的名字,两次)。

我尝试在选择中使用MIN和MAX,但这根本没有意义。

因此,从数据库中可能多次签入和签出的多行中,如何获取最新行并使用其dn字段?

这是我正在谈论的问题:

select 
    MAX(records.dn), 
    `records`.`din`, 
    `users`.`username`, 
    `users`.`id` as `user_id`, 
    DATE(records.created_at) AS date, 
    TIME(MIN(records.created_at)) AS first_log, 
    TIME(MAX(records.created_at)) AS last_log 
from `records` 
inner join `users` on `records`.`din` = `users`.`din` 
where records.created_at BETWEEN '2016-09-05 00:00:00' 
    AND '2016-09-08 00:00:00' 
group by `users`.`username`, DATE(records.created_at) 
order by `first_log` asc

(第一个选择列是我尝试做的,使用MAX)

这是包含一些样本数据的记录表:

the table

我如何实现我所寻找的目标?

1 个答案:

答案 0 :(得分:1)

substring_index() / group_concat()技巧可能完全符合您的要求:

select substring_index(group_concat(r.dn order by created_at desc), ',', 1) as last_dn, 
       u.username, u.id as `user_id`, 
       DATE(r.created_at) AS date, 
       TIME(MIN(r.created_at)) AS first_log, 
       TIME(MAX(r.created_at)) AS last_log 
from records r inner join
     users u
     on r.din = u.din 
where r.created_at >= '2016-09-05' and
      r.created_at < '2016-09-08' 
group by u.username, DATE(r.created_at) 
order by first_log asc;

如上所述,这有三个局限性:

  1. 它假设dn中没有逗号(可以通过使用不同的分隔符轻松修复)。
  2. 它假定一天用户的dn列表不会超过group_concat()字符串的最大长度。这也可以使用系统参数进行调整。
  3. last_dn是一个字符串,即使它不是原始类型。
  4. 但这种技巧在大多数情况下效果很好。参数group_concat_max_len是中间字符串的大小。它的默认值(此处为described)为1,024。对于多达一百个或更多整数,这应该没问题。这是一个会话参数,很容易更改。

    另请注意以下更改:

    • 我认为查询中不必要的反引号会让你更难阅读。
    • 使用表别名可以使查询更容易编写和阅读。
    • 我认为你不是between,因为它具有包容性。我猜你要在8日之前严格要求日期/时间值。