求连续操作(登录)数量(次数)最大的记录(用户)
昨晚上老同事聚会,一个同事说道一个面试问题没有一个人做出来,就是求连续日期登录次数最大的用户,同事说借助 rownumber即可求解,由于是喝酒聊天,也没有说详细的解决过程。今天早上想了下,终于想到了具体的解决思路。
登录时间里面有详细的时分秒数据,而我们的题目只要求连续的天数,所以使用DATEDIFF函数可以解决,
DATEDIFF(d,LoginTime,getdate()) as diffDate ,
有多个用户都在登录,因此应该以用户名为分区,登录时间为顺序来计算rownumber,因此,就是下面的表达式:
ROW_NUMBER() over(partition by Name order by LoginTime desc) as rn
关键问题来了,如何求得连续的登录情况?
如果是连续的记录,那么 diffDate- rn 肯定是相同的!
OK,果然这种方式很巧妙,那么我们最终的SQL写出来也不难了。
开始动手,先构造一个表,插入初始数据:
/*
求连续登录次数最多的用户
*/
create table UserLoginInfo(
ID int IDENTITY primary key,
Name varchar(50) not null,
LoginTime datetime not null
)
go
insert UserLoginInfo (Name,LoginTime)
values('zhang','2015-11-10 12:01:50')
,('li','2015-11-11 11:01:50')
,('wang','2015-11-9 11:01:50');
go
insert UserLoginInfo (Name,LoginTime) values
('zhang','2015-11-11 12:01:50'),
('li','2015-11-11 12:01:50'),
('wang','2015-11-11 11:01:50'),
('zhang','2015-11-12 12:01:50'),
('li','2015-11-13 13:01:50'),
('wang','2015-11-12 11:01:50'),
('zhang','2015-11-13 12:01:50'),
('li','2015-11-14 11:01:50'),
('wang','2015-11-14 11:01:50');
go
然后用下面的SQL得到结果:
select top 1
Name,diffRn,COUNT(diffRn)as LoginCount
from(
select Name,diffDate,rn, (diffDate-rn) as diffRn
from(
select ID,Name,
DATEDIFF(d,LoginTime,getdate()) as diffDate ,
ROW_NUMBER() over(partition by Name order by LoginTime desc) as rn
from UserLoginInfo
) t1
) t2
group by diffRn,Name
order by LoginCount desc
答案是:
Name diffRn LoginCount
zhang 14 4
如果注释掉 top 1,我们就知道这个结果的由来了:
Name diffRn LoginCount
zhang 14 4
li 13 3
wang 14 2
wang 15 1
li 14 1
wang 13 1
这个问题也可以衍生出 求连续登录的用户,或者求连续登录15天的用户(比如QQ的签到功能),是不是很熟悉呢?
实际上,上面这个查询,遇到一天登录多次的情况下,统计是不准确的,例如,构造下面的测试数据:
insert UserLoginInfo (Name,LoginTime) values
('zhang' ,'2015-11-10 12:01:50')
,('li' ,'2013-10-05 11:01:50')
,('li' ,'2013-10-06 11:01:50')
,('li' ,'2014-10-05 11:01:50')
,('li' ,'2014-10-06 11:01:50')
,('li' ,'2015-10-05 11:01:50')
,('li' ,'2015-10-06 11:01:50')
,('li' ,'2015-11-10 11:01:50')
,('li' ,'2015-11-11 11:01:50')
,('wang' ,'2015-11-09 11:01:50')
,('zhang' ,'2015-11-11 12:01:50')
,('li' ,'2015-11-11 12:01:50')
,('wang' ,'2015-11-11 11:01:50')
,('zhang' ,'2015-11-12 12:01:50')
,('li' ,'2015-11-13 13:01:50')
,('wang' ,'2015-11-12 11:01:50')
,('zhang' ,'2015-11-13 12:01:50')
,('li' ,'2015-11-14 11:01:50')
,('wang' ,'2015-11-14 11:01:50')
;
这时应该先去除某天的重复数据,才是正确的,所以查询应该做如下改进:
select --top 1
Name,diffRn,COUNT(diffRn)as LoginCount
from(
select Name,diffDate,rn, (diffDate-rn) as diffRn
from(
select Name,
diffDate,
ROW_NUMBER() over(partition by Name order by diffDate asc) rn
from (
select distinct Name,DATEDIFF(d,LoginTime,getdate()) as diffDate
from UserLoginInfo
) t0
) t1
) t2
group by diffRn,Name
order by LoginCount desc;
结果是:
Name diffRn LoginCount
zhang 14 4
wang 14 2
li 13 2
li 14 2
li 48 2
li 411 2
li 774 2
wang 13 1
wang 15 1
结果符合我们的预期,算是完整的答案了。
不知道别的同学还没有更好的解决方案?
-------------------------------------------
PS:如果你经常会在程序中写这样复杂的SQL,推荐你使用PDF.NET SOD框架的SQL-MAP功能,将SQL写在配置文件中,集中管理,并且方便跨数据库移植。
SOD框架 PDF.NET_SOD Ver 5.3.6.1125 已经发布,喜欢的朋友可以下载当前这个最新的稳定版本,有问题,可以加框架的QQ群:PDF.NET SOD高级群 18215717
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 基于laravel belongsTo使用详解
- laravel model模型定义实现开启自动管理时间created_at,updated_at
- laravel ORM关联关系中的 with和whereHas用法
- thinkPHP事务操作简单案例分析
- php 多个变量指向同一个引用($b = &$a)用法分析
- 浅谈laravel5.5 belongsToMany自身的正确用法
- 在 PHP 和 Laravel 中使用 Traits的方法
- Laravel 修改默认日志文件名称和位置的例子
- php 命名空间(namespace)原理与用法实例小结
- Laravel Eloquent ORM 实现查询表中指定的字段
- Yii框架 session 数据库存储操作方法示例
- 使用laravel指定日志文件记录任意日志
- php实现微信小程序授权登录功能(实现流程)
- PHP封装请求类实例分析【基于Yii框架】
- php 多继承的几种常见实现方法示例