Oracle 自连接小例 查询在任意10分钟内登陆超过10次的IP

需求说明

有一张记录登录行为的表:loginfo(ID,IP,LOGTIME),其中ID是主键,IP记录登录地址,LOGTIME记录登录时间
查询需求:查询在任意10分钟内登陆超过10次的IP

测试数据准备

create table loginfo as 
(select 01 ID,'192.168.1.1' IP, to_date('2014-10-01 07:30:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 02 ID,'192.168.1.1' IP, to_date('2014-10-01 07:31:10','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 03 ID,'192.168.1.1' IP, to_date('2014-10-01 07:31:50','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 04 ID,'192.168.1.1' IP, to_date('2014-10-01 07:32:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 05 ID,'192.168.1.1' IP, to_date('2014-10-01 07:33:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 06 ID,'192.168.1.1' IP, to_date('2014-10-01 07:34:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 07 ID,'192.168.1.1' IP, to_date('2014-10-01 07:35:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 08 ID,'192.168.1.1' IP, to_date('2014-10-01 07:35:20','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 09 ID,'192.168.1.1' IP, to_date('2014-10-01 07:35:50','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 10 ID,'192.168.1.1' IP, to_date('2014-10-01 07:36:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 11 ID,'192.168.1.1' IP, to_date('2014-10-01 07:37:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 12 ID,'192.168.1.1' IP, to_date('2014-10-01 07:40:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 13 ID,'192.168.1.1' IP, to_date('2014-10-01 07:40:20','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 14 ID,'192.168.1.1' IP, to_date('2014-10-01 07:41:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 15 ID,'192.168.1.1' IP, to_date('2014-10-01 07:42:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 16 ID,'192.168.1.1' IP, to_date('2014-10-01 07:45:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 17 ID,'192.168.1.1' IP, to_date('2014-10-01 07:46:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 18 ID,'192.168.1.1' IP, to_date('2014-10-01 07:47:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 19 ID,'192.168.1.1' IP, to_date('2014-10-01 07:48:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 20 ID,'192.168.1.2' IP, to_date('2014-10-01 07:30:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 21 ID,'192.168.1.2' IP, to_date('2014-10-01 07:31:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 22 ID,'192.168.1.2' IP, to_date('2014-10-01 07:32:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 23 ID,'192.168.1.2' IP, to_date('2014-10-01 07:35:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 24 ID,'192.168.1.2' IP, to_date('2014-10-01 07:36:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 25 ID,'192.168.1.2' IP, to_date('2014-10-01 07:36:20','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 26 ID,'192.168.1.2' IP, to_date('2014-10-01 07:37:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 27 ID,'192.168.1.2' IP, to_date('2014-10-01 07:38:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 28 ID,'192.168.1.2' IP, to_date('2014-10-01 07:39:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 29 ID,'192.168.1.2' IP, to_date('2014-10-01 07:39:30','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 30 ID,'192.168.1.2' IP, to_date('2014-10-01 07:40:20','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 31 ID,'192.168.1.2' IP, to_date('2014-10-01 07:41:00','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual union all
 select 32 ID,'192.168.1.2' IP, to_date('2014-10-01 07:42:20','YYYY-MM-DD HH24:MI:SS') as LOGTIME from dual
 );

推导过程

1° 使用自连接,自己连接自己,做笛卡尔积,生成m*m条记录,从select子句中剔除掉不需要的列:

select t1.IP, t1.ID ID1, t2.ID ID2, 
       t1.LOGTIME time1, t2.LOGTIME time2
  from loginfo t1, loginfo t2;

这里写图片描述

2° 观察生成的笛卡尔积,根据需求,不同的IP之间做比较是没有意义的,因此加入筛选条件 t1.IP=t2.IP
为了更方便看出记录的规律,加入order by语句:

select t1.IP, t1.ID ID1, t2.ID ID2, 
       t1.LOGTIME time1, t2.LOGTIME time2
  from loginfo t1, loginfo t2
 where t1.IP=t2.IP
 order by t1.ID,t2.ID;

3° 要看出是否是10分钟之内的连续登陆,需要比较两表的LOGTIME关系
要求第二张表的登录时间在第一张表的登录时间的十分钟内
因此加入筛选条件 t1.LOGTIME+1/24/60*10>=t2.LOGTIME:

select t1.IP, t1.ID ID1, t2.ID ID2, 
       t1.LOGTIME time1, t2.LOGTIME time2
  from loginfo t1, loginfo t2
 where t1.IP=t2.IP
   and t1.LOGTIME+1/24/60*10>=t2.LOGTIME
 order by t1.ID,t2.ID;

这里写图片描述

4° 主键列 ID 唯一标识一次登录行为,那么 ID1>ID2 则表示同一 IP 的后一次登录和前一次登录做比较,无意义
同时 ID1=ID2 则表示同一 IP 的同一次登录做比较,也是没有意义的,因此加入筛选条件 ID1

select t1.IP, t1.ID ID1, t2.ID ID2, 
       t1.LOGTIME time1, t2.LOGTIME time2
  from loginfo t1, loginfo t2
 where t1.IP=t2.IP
   and t1.LOGTIME+1/24/60*10>=t2.LOGTIME
   and t1.id<t2.id
 order by t1.ID,t2.ID;

这里写图片描述

5° 此时就能看出10分钟内连续登陆超过10次的IP了
同一IP,列 ID1 的某个值如果重复出现超过9次,则该IP满足条件
需要注意理解此处的9的由来,超过10次的连续登录只要大于等于9次就可以了
如:192.168.1.1,ID1=1 出现11次,一直到 ID2=12
就是说该IP的第1次登录时间+10分钟大于等于第12次的登录时间
第1次登录之后的十分钟之内又连续登陆了11次,连续登陆12次
根据IP和ID1分组,求count(*) 10分钟内的连续登陆次数,筛选出大于等于10次的记录:

select t1.IP, t1.ID, count(*)
  from loginfo t1, loginfo t2
 where t1.IP=t2.IP
   and t1.LOGTIME+1/24/60*10>=t2.LOGTIME
   and t1.id<t2.id
 group by t1.IP, t1.ID
having count(*)>=9
 order by t1.IP, t1.ID;

这里写图片描述

6° 如查询结果所示,ID=1 的登录行为后,10分钟内又登陆了11次,连续登陆12次
依次类推:ID=2 的登录行为后,10分钟内又登陆了12次,连续登陆13次
但是我们不需要显示第几次登录的信息,也不需要显示该次登陆后连续登陆了多少次的信息
最终需要展示的只是IP信息,因此直接对IP滤重即可:

select distinct t1.IP
  from loginfo t1, loginfo t2
 where t1.IP=t2.IP
   and t1.LOGTIME+1/24/60*10>=t2.LOGTIME
   and t1.id<t2.id
 group by t1.IP, t1.ID
having count(*)>=9;

[TOC]

猜你喜欢

转载自blog.csdn.net/zwjzqqb/article/details/80091741