有一個用戶登錄流水表結構如下:
create table hy_login_flow( id number(4,0) not null primary key, name nvarchar2(20) not null, logindate date not null)
這樣給它充值:
insert into hy_login_flow(id,name,logindate) values('1','A001',to_date('2020-01-01','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('2','A001',to_date('2020-01-02','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('11','A001',to_date('2020-01-03','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('3','A001',to_date('2020-01-05','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('4','A001',to_date('2020-01-06','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('5','B001',to_date('2020-01-01','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('6','B001',to_date('2020-01-02','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('7','B001',to_date('2020-01-05','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('8','C001',to_date('2020-01-01','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('9','C001',to_date('2020-01-02','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('10','D001',to_date('2020-01-07','yyyy-MM-dd'));
然后我們觀察這些記錄:
可以發現,A001用戶從2020-1-1~2020-1-3連續登錄了三天,從2020-01-05~2020-01-06連續登錄了兩天;
B001用戶從2020-1-1-2020-1-2連續登錄了兩天,在2020-01-05只登錄了一天;
C001用戶從2020-1-01~2020-01-02連續登錄了兩天;
D001用戶只在2020-01-07登錄了一天。
我們的任務是編寫sql把用戶連續登錄的天數找出來。
首先,我們按用戶分組,按登錄時間升序排列一下,因為不同用戶的記錄毫無關系。
觀察上表,我們可以發現,連續登錄的用戶,他的logindate減去seq是一個定數,這是解決問題的關鍵所在。
於是我們再查了一次:
多出的BasicDate列就是用logindate減去seq的差值,我們可以發現連續登錄的記錄,basicdate都是一樣的。
接下來就好辦了,按name和basicdate分組,求記錄數就可以了。
最終SQL:
select b.name,count(*) from (select a.*,a.logindate-a.seq as basicdate from (select row_number() over (partition by name order by logindate) as seq,name,logindate from hy_login_flow) a) b group by b.name,b.basicdate order by b.name
查詢結果:
本文用到的全部SQL:
create table hy_login_flow( id number(4,0) not null primary key, name nvarchar2(20) not null, logindate date not null) insert into hy_login_flow(id,name,logindate) values('1','A001',to_date('2020-01-01','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('2','A001',to_date('2020-01-02','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('11','A001',to_date('2020-01-03','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('3','A001',to_date('2020-01-05','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('4','A001',to_date('2020-01-06','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('5','B001',to_date('2020-01-01','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('6','B001',to_date('2020-01-02','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('7','B001',to_date('2020-01-05','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('8','C001',to_date('2020-01-01','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('9','C001',to_date('2020-01-02','yyyy-MM-dd')); insert into hy_login_flow(id,name,logindate) values('10','D001',to_date('2020-01-07','yyyy-MM-dd')); commit; select * from hy_login_flow select row_number() over (partition by name order by logindate) as seq,name,logindate from hy_login_flow select a.*,a.logindate-a.seq as basicdate from (select row_number() over (partition by name order by logindate) as seq,name,logindate from hy_login_flow) a select b.name,count(*) from (select a.*,a.logindate-a.seq as basicdate from (select row_number() over (partition by name order by logindate) as seq,name,logindate from hy_login_flow) a) b group by b.name,b.basicdate order by b.name
參考資料:
1.https://bbs.csdn.net/topics/396162708?page=1#post-411014646 引發問題的帖子。
2.https://blog.csdn.net/padluo/article/details/81113438 受啟發的文章,在此感謝作者無意中的指點。
--2020-03-19--