Skip to content

1 案例

有一张表记录了所有员工的打卡时间,现在需要统计每天,打卡最早的员工。

2 样本数据

sql
DROP TABLE IF EXISTS `t_sign_record`;
CREATE TABLE `t_sign_record`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(50) DEFAULT NULL,
  `sign_time` datetime(0) DEFAULT NULL,
  `dt` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8;

INSERT INTO `t_sign_record` VALUES (1, '张三', '2021-12-21 08:50:19', '2021-12-21');
INSERT INTO `t_sign_record` VALUES (2, '张三', '2021-12-22 08:30:03', '2021-12-22');
INSERT INTO `t_sign_record` VALUES (3, '李四', '2021-12-21 08:43:00', '2021-12-21');
INSERT INTO `t_sign_record` VALUES (4, '李四', '2021-12-22 08:29:37', '2021-12-22');
INSERT INTO `t_sign_record` VALUES (5, '王五', '2021-12-22 09:04:43', '2021-12-22');

3 min()定位

sql
-- 先根据dt分组,计算min值
WITH t_max_time AS ( SELECT dt, min( sign_time ) AS `sign_time` FROM t_sign_record GROUP BY dt ) 
-- 然后关联查询即可
SELECT
	t_sign_record.dt,
	t_sign_record.user_name,
	t_sign_record.sign_time 
FROM
	t_sign_record
	INNER JOIN t_max_time ON t_sign_record.dt = t_max_time.dt 
	AND t_sign_record.sign_time = t_max_time.sign_time;

注意:min值可能存在多条记录。

4 row_number()精确行码

sql
-- 先根据dt分组,sign_time升序计算排序
WITH t_sign_rank AS ( 
	SELECT 
		*, 
		ROW_NUMBER() OVER (PARTITION BY dt ORDER BY sign_time) row_num 	
	FROM t_sign_record 
) 
-- 然后取row_num=1的数据行就是每天的最早打卡记录
SELECT
	dt,
	user_name,
	sign_time 
FROM
	t_sign_rank 
WHERE
	row_num = 1;

通过控制row_num的范围,可以方便地获取TOP(n)记录。

5 rank()排名

如果要获取某些天,打卡前2名的员工,上述方式均不适用。

因为某个名次可能出现多人,我们重新构造下样本数据;

iduser_namesign_timedt
1张三2021-12-21 08:50:192021-12-21
2张三2021-12-22 08:20:032021-12-22
3李四2021-12-21 08:43:002021-12-21
4李四2021-12-22 08:29:372021-12-22
5王五2021-12-22 08:29:372021-12-22

基于rank()函数可以实现;

sql
-- 先根据dt分组,sign_time升序计算排名
WITH t_sign_rank AS ( 
	SELECT 
		*, 
		rank() OVER (PARTITION BY dt ORDER BY sign_time) rank_num
	FROM t_sign_record 
) 
-- 然后取rank_num<=2的数据行就是每天的最早打卡记录
SELECT
	dt,
  	rank_num,
	user_name,
	sign_time 
FROM
	t_sign_rank 
WHERE
	rank_num <= 2;

最终结果如下;

dtrank_numuser_namesign_time
2021-12-211李四2021-12-21 08:43:00
2021-12-212张三2021-12-21 08:50:19
2021-12-221张三2021-12-22 08:20:03
2021-12-221李四2021-12-22 08:29:37
2021-12-222王五2021-12-22 08:29:37

6 参考资料

基于 MIT 许可发布