如何查询出连续登陆的最长天数
2012-04-21 14:23
393 查看
最近遇到不少关于解决连续登陆天数的帖子。这类问题实际也就是我们经常遇到的孤岛问题的一个变种
解决这类问题,我们有一个最基本的思路:
step 1:找出间断之后的点,为他们分配行号(这是孤岛的起点)
step 2:找出间断之前的点,为他们分配行号(这是孤岛的终点)
step 3:以行号相等作为条件,匹配孤岛的起点和终点
在实现以上三步后,我们基本上就能解决这类问题了,一下我以三种方法演示:
/*
name logindate
a1 2011-1-2
a1 2011-1-3
a1 2011-1-4
a1 2011-1-7
a1 2011-1-12
a1 2011-1-13
a1 2011-1-16
a2 2011-1-7
a2 2011-1-8
a2 2011-1-10
a2 2011-1-11
a2 2011-1-13
a2 2011-1-24
---------------------------------------------
我需要的结果是:
name start_day end_day logindays
a1 2011-1-2 2011-1-4 3
a2 2011-1-7 2011-1-8 2
a2 2011-1-10 2011-1-11 2
*/
--> 测试数据:[tbl]
if object_id('[tbl]') is not null drop table [tbl]
create table [tbl]([name] varchar(2),[logindate] date)
insert [tbl]
select 'a1','2011-1-2' union all
select 'a1','2011-1-3' union all
select 'a1','2011-1-4' union all
select 'a1','2011-1-7' union all
select 'a1','2011-1-12' union all
select 'a1','2011-1-13' union all
select 'a1','2011-1-16' union all
select 'a2','2011-1-7' union all
select 'a2','2011-1-8' union all
select 'a2','2011-1-10' union all
select 'a2','2011-1-11' union all
select 'a2','2011-1-13' union all
select 'a2','2011-1-24'
--方法1
;with t as(
select [name],[logindate],
(select min(b.[logindate]) from tbl b
where b.[logindate]>=a.[logindate] and b.name=a.name
and not exists (select * from tbl c
where c.[logindate]=dateadd(dd,1,b.[logindate]) and c.name=b.name)) as grp
from tbl a
),m
as(
select [name],min([logindate]) as start_day,max(grp) as end_day
from t group by grp,name
)
select *,(datediff(dd,start_day,end_day)+1) as logindays from m a
where (datediff(dd,start_day,end_day)+1) in(
select max(datediff(dd,start_day,end_day)+1) from m b
where a.name=b.name)
---------------------------------------------------------------------------
---------------------------------------------------------------------------
--方法2
declare @date datetime
select @date = min(logindate) from tbl
;with ach as
(
select [name],logindate,
id=row_number() over (partition by [name] order by logindate)
from tbl
),
t as(
select [name],min(logindate) mindate,max(logindate) maxdate,
(datediff(dd,min(logindate),max(logindate))+1) dddate
from ach
group by [name],datediff(dd,@date,logindate)-id
--order by [name],mindate
)
select * from t a where dddate in(select max(dddate) from t b where
a.name=b.name)
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--方法3
;with t as
(
select name,[logindate],dateadd(dd,
-row_number()over(partition by name
order by [logindate]),[logindate]) as diff from tbl
),
m as(
select name,min([logindate]) as start_day,max([logindate]) as end_day,
(datediff(dd,min([logindate]),max([logindate]))+1) as logindays
from t
group by name,diff
)
select * from m a
where logindays in(select MAX(logindays) from m b
where a.name=b.name)
/*
name start_day end_day logindays
a1 2011-01-02 2011-01-04 3
a2 2011-01-10 2011-01-11 2
a2 2011-01-07 2011-01-08 2
*/
关于连续登陆问题也就是时间孤岛问题,所以我们的解决思路就等同于求孤岛。
在学习的过程中我建议大家能抓住最基本的方法,不要一味的追求最简单的方法。
任何一个简单的方法都是建立在一定得基础知识和熟练程度上的,只有当你熟练
掌握了最基本的东西才可能去发现更简单的办法。
来自:http://blog.csdn.net/travylee/article/details/7460030
解决这类问题,我们有一个最基本的思路:
step 1:找出间断之后的点,为他们分配行号(这是孤岛的起点)
step 2:找出间断之前的点,为他们分配行号(这是孤岛的终点)
step 3:以行号相等作为条件,匹配孤岛的起点和终点
在实现以上三步后,我们基本上就能解决这类问题了,一下我以三种方法演示:
/*
name logindate
a1 2011-1-2
a1 2011-1-3
a1 2011-1-4
a1 2011-1-7
a1 2011-1-12
a1 2011-1-13
a1 2011-1-16
a2 2011-1-7
a2 2011-1-8
a2 2011-1-10
a2 2011-1-11
a2 2011-1-13
a2 2011-1-24
---------------------------------------------
我需要的结果是:
name start_day end_day logindays
a1 2011-1-2 2011-1-4 3
a2 2011-1-7 2011-1-8 2
a2 2011-1-10 2011-1-11 2
*/
--> 测试数据:[tbl]
if object_id('[tbl]') is not null drop table [tbl]
create table [tbl]([name] varchar(2),[logindate] date)
insert [tbl]
select 'a1','2011-1-2' union all
select 'a1','2011-1-3' union all
select 'a1','2011-1-4' union all
select 'a1','2011-1-7' union all
select 'a1','2011-1-12' union all
select 'a1','2011-1-13' union all
select 'a1','2011-1-16' union all
select 'a2','2011-1-7' union all
select 'a2','2011-1-8' union all
select 'a2','2011-1-10' union all
select 'a2','2011-1-11' union all
select 'a2','2011-1-13' union all
select 'a2','2011-1-24'
--方法1
;with t as(
select [name],[logindate],
(select min(b.[logindate]) from tbl b
where b.[logindate]>=a.[logindate] and b.name=a.name
and not exists (select * from tbl c
where c.[logindate]=dateadd(dd,1,b.[logindate]) and c.name=b.name)) as grp
from tbl a
),m
as(
select [name],min([logindate]) as start_day,max(grp) as end_day
from t group by grp,name
)
select *,(datediff(dd,start_day,end_day)+1) as logindays from m a
where (datediff(dd,start_day,end_day)+1) in(
select max(datediff(dd,start_day,end_day)+1) from m b
where a.name=b.name)
---------------------------------------------------------------------------
---------------------------------------------------------------------------
--方法2
declare @date datetime
select @date = min(logindate) from tbl
;with ach as
(
select [name],logindate,
id=row_number() over (partition by [name] order by logindate)
from tbl
),
t as(
select [name],min(logindate) mindate,max(logindate) maxdate,
(datediff(dd,min(logindate),max(logindate))+1) dddate
from ach
group by [name],datediff(dd,@date,logindate)-id
--order by [name],mindate
)
select * from t a where dddate in(select max(dddate) from t b where
a.name=b.name)
--------------------------------------------------------------------------
--------------------------------------------------------------------------
--方法3
;with t as
(
select name,[logindate],dateadd(dd,
-row_number()over(partition by name
order by [logindate]),[logindate]) as diff from tbl
),
m as(
select name,min([logindate]) as start_day,max([logindate]) as end_day,
(datediff(dd,min([logindate]),max([logindate]))+1) as logindays
from t
group by name,diff
)
select * from m a
where logindays in(select MAX(logindays) from m b
where a.name=b.name)
/*
name start_day end_day logindays
a1 2011-01-02 2011-01-04 3
a2 2011-01-10 2011-01-11 2
a2 2011-01-07 2011-01-08 2
*/
关于连续登陆问题也就是时间孤岛问题,所以我们的解决思路就等同于求孤岛。
在学习的过程中我建议大家能抓住最基本的方法,不要一味的追求最简单的方法。
任何一个简单的方法都是建立在一定得基础知识和熟练程度上的,只有当你熟练
掌握了最基本的东西才可能去发现更简单的办法。
来自:http://blog.csdn.net/travylee/article/details/7460030
相关文章推荐
- 如何查询出连续登陆的最长天数
- 连续时间查询问题-查询一个用户连续登陆天数超过N天的用户
- mysql如何查询两个日期之间最大的连续登录天数
- mysql如何查询两个日期之间最大的连续登录天数
- 传入用户id查询连续签到天数
- Oracle如何查询登陆客户端的机器名?
- Mysql如何查询连续时间内的次数
- 如何使用SQL语句查询连续编号中缺失的编号?
- Mysql如何查询连续的时间次数
- 如何求最长连续公共子序列和最长连续子字符串
- 如何sql查询出连续号码段 (单号连续性检查)
- poj 3667 最长空白段+查询最左连续段
- 关于到今天考勤系统连续上班天数的问题或者连续登陆天数的问题(sql)
- 获取连续登陆天数,连续签到天数 ,方法优化
- 连续最长加班天数
- HDU 3308 线段树 最长连续上升子序列 单点更新 区间查询
- 数据库中如何使用SQL查询连续号码段
- mysql查询最大连续出现天数
- 一个有趣的 SQL 查询(查询7天连续登陆)
- 关于如何用sql语句查询出连续的一串数字