--==========================================

需求:有一个用户登陆日志表,记录用户每次登陆时间,然后想查找用户按天连续登陆的情况,找出每次连续登陆的最早时间和最后时间以及连续登陆天数。

--===========================================

由于长久未写此类SQL,有点手生,本着走一步算一步的精神,慢慢来。

首先查看日志表

SELECT [Uid]
,[loginDate]
FROM [dbo].[Member_LoginLog]
WHERE [UID]=268

由于按天计算连续登陆,表中时间精确到毫秒,很难肉眼看出数据是否连续,于是考虑转换数据

而又由于我们只关心最早登陆时间和最后登陆时间,因此我们可以先按照天来统计用户最早登陆时间和最后登陆时间,并将时间转换成对应天数

--==============================================
--统计出用户每天最早登陆时间和最后登陆时间
SELECT T1.[UID]
,DATEDIFF(DAY,'2014-01-01',LoginDate) AS DiffDays
,MAX(LoginDate) AS MaxLoginDate
,MIN(LoginDate) AS MinLoginDate
INTO [dbo].[Member_LoginLog_Status1]
FROM [dbo].[Member_LoginLog] T1
GROUP BY T1.[UID],DATEDIFF(DAY,'2014-01-01',LoginDate)
--======================================
--查看效果
SELECT [UID]
,[DiffDays]
,[MaxLoginDate]
,[MinLoginDate]
FROM [dbo].[Member_LoginLog_Status1]
WHERE UID=268

从上图很容易看出第二天没连续登陆,是不是很容易看啊

接下来就是查找联系的天数了,如果我们按照UID分组,然后对DiffDays来排序求出排名来,依据DiffDays的增长量和RID量便可以判断出天数是否连续

SELECT
ROW_NUMBER()OVER(PARTITION BY UID ORDER BY [DiffDays] ASC) AS RID,
T1.*
FROM [dbo].[Member_LoginLog_Status1] T1
WHERE [UID]=268

这样我们便可以使用表的自连接来查找连续的登录,由于需要按照用户和天数来算出排名,因此我们可以先建立索引

CREATE CLUSTERED INDEX CIX_UID_Days ON
[dbo].[Member_LoginLog_Status1]
(
[UID],[DiffDays]
)

然后再求连续区间:

--==========================================
--查找连续的登录
;WITH Tem AS(
SELECT
ROW_NUMBER()OVER(PARTITION BY UID ORDER BY [DiffDays] ASC) AS RID,
T1.*
FROM [dbo].[Member_LoginLog_Status1] T1
)
,Tem1 AS(
SELECT ROW_NUMBER()OVER(
PARTITION BY T1.[UID],T1.[DiffDays]
ORDER BY T2.[diffdays]-T1.[diffdays] DESC) AS RID,
T1.[UID],
T1.MinLoginDate,
T2.MaxLoginDate,
T1.[diffdays] AS MinDiffDays,
T2.[diffdays] AS MAXDiffDays
FROM Tem AS T1
INNER JOIN Tem AS T2
ON T1.UID=T2.UID
AND T1.[diffdays]<=T2.[diffdays]
AND T2.[diffdays]-T1.[diffdays]= T2.RID-T1.RID
)
SELECT
[UID],
MinLoginDate,
MaxLoginDate,
MinDiffDays,
MAXDiffDays
INTO [dbo].[Member_LoginLog_Status2]
FROM Tem1 AS T1
WHERE T1.RID=1
--=========================================
--检查结果
SELECT [UID]
,[MinLoginDate]
,[MaxLoginDate]
,[MinDiffDays]
,[MAXDiffDays]
FROM [dbo].[Member_LoginLog_Status2]
WHERE [UID]=268

找出连续的区间后,我们会发现有很多区间不是最大连续区间,如第5天到第17天连续,但是比之更大的区间还有第3天到第17天,对于这种问题,解决办法就是依据maxDiffDays分组,求出最小的minDiffDays

由于此时要按照用户和maxDiffDays分组,然后按照MinDiffDays排序求最小值,因此先建立索引

CREATE CLUSTERED INDEX CIX_UID_MAXDiffDays
ON [AccMain_101].[dbo].[Member_LoginLog_Status2]
([UID],MAXDiffDays,MinDiffDays ASC)

然后再查询:

--====================================
--求出最大连续区间
;WITH CTE1 AS(
SELECT
ROW_NUMBER()OVER(PARTITION BY [UID],MAXDiffDays ORDER BY MinDiffDays ASC) AS RID,
[UID],
MinLoginDate,
MaxLoginDate,
MinDiffDays,
MAXDiffDays
FROM [AccMain_101].[dbo].[Member_LoginLog_Status2] AS T1
)
INSERT INTO [dbo].[Member_LoginLog_Status3]
([Uid]
,[firstLoginDate]
,[lastLoginDate]
,[loginNumber])
SELECT [UID],
MinLoginDate,
MaxLoginDate,
T1.MAXDiffDays-MinDiffDays AS ContinueDays
FROM CTE1 T1
WHERE T1.RID=1
--==================================
--查看结果
SELECT [Uid]
,[firstLoginDate]
,[lastLoginDate]
,[loginNumber]
FROM [dbo].[Member_LoginLog_Status3]
WHERE [UID]=268

查询结果:

结果正是我们想要的,因此打完收工,回家吃饭。

--===============================================

总结:其实查找连续或查找孤岛这类原理,都是利用自连接然后看增长是否连续,多折腾几遍就好。

--===============================================

wwwwgou的回复中,指出一条更快捷的计算方式,同样使用排名来计算,但不使用关联,而是计算排名与登陆天数的差值,如果登陆天数连续增长,则排名也连续增长,两者的差值保持不变;如果登陆天数不连续,则登陆天数增长的值就会比排名增长的值高,这时两者的差值就会变大。

如下图:

随着天数不连续的次数增加,[天数-排名]的值会不断增大,因此可以使用[天数-排名]来分组,便可以定位到连续区间。

PS: 不会出现两个不同连续区间的[天数-排名]值一样的情况

查找代码:

--========================================
--感谢wwwwgou提供,
--此代码已略做修改
SELECT
[Uid],
mindt = MIN(mindt),
maxdt = MAX(maxdt),
logdays = COUNT(*)
FROM
(
SELECT
[Uid],
RowNo = ROW_NUMBER()
OVER(PARTITION BY [Uid]
ORDER BY DATEDIFF(DAY,'2014-01-01', loginDate)),
DiffDay = DATEDIFF(DAY,'2014-01-01', loginDate),
mindt = MIN(loginDate),
maxdt = MAX(loginDate)
FROM dbo.Member_LoginLog
GROUP BY [Uid], DATEDIFF(DAY,'2014-01-01', loginDate)
) T
GROUP BY [Uid], [RowNo] - DiffDay
ORDER BY [Uid], minDt

对wwwwgou筒子再次表示婶婶地感谢。

--===============================================

请原谅我苍白的讲解,让您们只能看代码。

妹子骚猴就上,不要着急。

TSQL--查找连续登陆用户的更多相关文章

  1. 大数据学习day25------spark08-----1. 读取数据库的形式创建DataFrame 2. Parquet格式的数据源 3. Orc格式的数据源 4.spark_sql整合hive 5.在IDEA中编写spark程序(用来操作hive) 6. SQL风格和DSL风格以及RDD的形式计算连续登陆三天的用户

    1. 读取数据库的形式创建DataFrame DataFrameFromJDBC object DataFrameFromJDBC { def main(args: Array[String]): U ...

  2. Redis简单案例(三) 连续登陆活动的简单实现

    连续登陆活动,或许大家都不会陌生,简单理解就是用户连续登陆了多少天之后,系统就会送一些礼品给相应的用户.最常见的 莫过于游戏和商城这些.游戏就送游戏币之类的东西,商城就送一些礼券.正值国庆,应该也有不 ...

  3. mysql 查看当前登陆用户匹配原则及权限user()与current_user()

    Mysql在进行登陆时,会去匹配mysql库中的user表,并赋予相应的权限,但是怎么知道我们当时的登陆的用户名及相应的权限呢? 在Mysql中,有两个函数,一个是user(),一个是current_ ...

  4. finger---用于查找并显示用户信息

    finger finger命令用于查找并显示用户信息.包括本地与远端主机的用户皆可,帐号名称没有大小写的差别.单独执行finger指令,它会显示本地主机现在所有的用户的登陆信息,包括帐号名称,真实姓名 ...

  5. JavaWeb-SpringSecurity在数据库中查询登陆用户

    系列博文 项目已上传至guthub 传送门 JavaWeb-SpringSecurity初认识 传送门 JavaWeb-SpringSecurity在数据库中查询登陆用户 传送门 JavaWeb-Sp ...

  6. AlwaysOn添加高可用性自定义登陆用户的方法

    1.在主服务器添加自定义登陆用户,比如TestUser 2.在主服务器执行如下SQL,在master数据库创建存储过程sp_hexadecimal,sp_help_revlogin USE maste ...

  7. linux下登陆用户的行为信息—w和who命令详解

    查看用户的操作系统管理员若想知道某一时刻用户的行为,只需要输入命令w 即可,在SHELL终端中输入如下命令: [root@localhost ~]# w 可以看到执行w命令及显示结果. 命令信息含义上 ...

  8. 查找oracle自己用户的表

    查找oracle自己用户的表 select table_name from user_tables;

  9. mysql创建远程登陆用户并授权

    在创建安装微擎的过程中,针对第四步 创建远程登陆用户并授权        > grant all PRIVILEGES on database.* to root@'127.0.0.1'  id ...

随机推荐

  1. oracle以逗号分隔查询结果列表

    select wmsys.wm_concat(id) from table_name where id >= 5000 and id < 6000

  2. SVN常见问题I

    TortoiseSVN ->Settings 把权限给清空,不让用户A的权限再保留在里面 右键->SVN Checkout 之后需要在A账户和B账户之间来回切换

  3. np.array()

    将列表list或元组tuple转换为 ndarray 数组. numpy.array(object, dtype=None, copy=True, order=None, subok=False, n ...

  4. TZOJ 4855 排座椅(贪心)

    描述 上课的时候总有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来后,只有有限的D对同学上课时会交头接耳.同学们在教室 ...

  5. 动态输出的javascript中alert文本的换行问题

    这个简单<%out.println("<script>alert('姓名:xx\\n性别:女\\n爱好:吃\\n')</script>");%> ...

  6. Python学习记录day7

    目录 Python学习记录day7 1. 面向过程 VS 面向对象 编程范式 2. 面向对象特性 3. 类的定义.构造函数和公有属性 4. 类的析构函数 5. 类的继承 6. 经典类vs新式类 7. ...

  7. 通过dockerfile构建nginx

    上次 利用命令行的形式来构建nginx服务, http://www.cnblogs.com/loveyouyou616/p/6806788.html 这次利用dockerfile文件来构建nginx服 ...

  8. swagger ui js 错误:Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.

    经过排查,引发此错误的原因是,表中有一个字段名称为“NodeName”,应该是在前台xml解析时引发冲突所致.我的解决办法是: 修改列名,修改映射. 如下: [Column("NodeNam ...

  9. @RequestMapping 介绍

    RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上.用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径. RequestMapping注解有六个属性,下面我们把她 ...

  10. TPM、read counts、RPKM/FPKM你选对了吗?

    TPM.read counts.RPKM/FPKM你选对了吗? 已有 3940 次阅读 2017-12-15 15:04 |个人分类:RNA-seq|系统分类:科普集锦|关键词:RNA-seq| RN ...