ITPub博客

首页 > 数据库 > MySQL > MySQL连续范围问题

MySQL连续范围问题

原创 MySQL 作者:壹頁書 时间:2014-12-31 01:35:05 1 删除 编辑
MySQL技术内幕 SQL编程 58页
首先创建实验表
create table t(a int primary key);
insert into t values(1);
insert into t values(2);
insert into t values(3);
insert into t values(100);
insert into t values(101);
insert into t values(103);
insert into t values(104);
insert into t values(105);
commit;

实验目标是求数字的连续范围,以上面的数据为例,应该求得的连续范围为
1-3
100-101
103-105

第一步,给数据增加行号
select a,@a:=@a+1 rn from t,(select @a:=0) as a;


第二步,求得数据与行号的差值
  1. select a,rn,a-rn diff from
  2. (
  3.     select a,@a:=@a+1 rn from t,(select @a:=0) as a

  4. ) b;


第三步 获得结果
  1. select min(a) start_range,max(a) end_range
  2. from
  3. (
  4.     select a,rn,a-rn diff from
  5.     (
  6.         select a,@a:=@a+1 rn from t,(select @a:=0) as a
  7.     ) b
  8. ) c group by diff;



用之前的签到实验说明这个连续范围的用法.
http://blog.itpub.net/29254281/viewspace-1379159/

award_chance_history是活动的签到表,userid记录用户的ID,createtime记录用户的签到时间.
实验求每个用户的连续签到时间.
  1. create table award_chance_history
  2. (
  3.     id int primary key auto_increment,
  4.     userid int,
  5.     createtime datetime
  6. );

  7. insert into award_chance_history(userid,createtime)
  8. select ceil(rand()*10000),str_to_date('2014-12-15','%Y-%m-%d')+interval ceil(rand()*10000) minute from nums where id<30;
  1. insert into award_chance_history(userid,createtime)
  2. select userid,createtime + interval ceil(rand()*10) day from award_chance_history,nums
  3. where nums.id <10 order by rand() limit 150;

第一步,获取用户每天的签到情况
获取用户签到时间和现在时间的差值,并且用distinct过滤用户在一天内多次签到的记录
select
distinct
userid,
date_format(createtime,'%Y-%m-%d') createtime,
datediff(createtime,now()) diff
from award_chance_history order by userid,createtime

第二步,模拟分析函数,每个用户都产生一个自己的序列
select
b.*,
@gid := @cgid,
@cgid := b.userid,
if(@gid = @cgid, @rank := @rank + 1, @rank := 1)  rank,
b.diff-@rank flag from (
    select
    distinct
    userid,
    date_format(createtime,'%Y-%m-%d') createtime,
    datediff(createtime,now()) diff
    from award_chance_history order by userid,createtime
) b, (SELECT @gid := 1, @cgid := 1, @rank := 1) as a

diff和rank序列相减,作为flag字段,flag相同说明用户是连续签到.
如下图的249用户,在16,17日连续签到,他们的flag都是-16.


第三步,根据分组得到连续签到的结果

  1. select userid,min(c.createtime),max(c.createtime),count(*) from
  2. (
  3.     select
  4.     b.*,
  5.     @gid := @cgid,
  6.     @cgid := b.userid,
  7.     if(@gid = @cgid, @rank := @rank + 1, @rank := 1) rank,
  8.     b.diff-@rank flag from (
  9.         select
  10.         distinct
  11.         userid,
  12.         date_format(createtime,'%Y-%m-%d') createtime,
  13.         datediff(createtime,now()) diff
  14.         from award_chance_history order by userid,createtime
  15.     ) b, (SELECT @gid := 1, @cgid := 1, @rank := 1) as a
  16. ) c group by userid,flag;



第四步,求每个用户最长的连续签到时间段
在第三步的基础上,再模拟一次分析函数

  1. select * from (
  2.     select d.*,
  3.     @ggid := @cggid,
  4.     @cggid := d.userid,
  5.     if(@ggid = @cggid, @grank := @grank + 1, @grank := 1) grank
  6.     from
  7.     (
  8.         select userid,min(c.createtime) begin_date ,max(c.createtime) end_date,count(*) c from
  9.         (
  10.             select
  11.             b.*,
  12.             @gid := @cgid,
  13.             @cgid := b.userid,
  14.             if(@gid = @cgid, @rank := @rank + 1, @rank := 1) rank,
  15.             b.diff-@rank flag from (
  16.                 select
  17.                 distinct
  18.                 userid,
  19.                 date_format(createtime,'%Y-%m-%d') createtime,
  20.                 datediff(createtime,now()) diff
  21.                 from award_chance_history order by userid,createtime
  22.             ) b, (SELECT @gid := 1, @cgid := 1, @rank := 1) as a
  23.         ) c group by userid,flag
  24.         order by userid,count(*) desc
  25.     ) d,(SELECT @ggid := 1, @cggid := 1, @grank := 1) as e
  26. )f
  27. where grank=1;


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29254281/viewspace-1385638/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: SQL星期数问题
请登录后发表评论 登录
全部评论

注册时间:2013-10-19

  • 博文量
    620
  • 访问量
    6339948