首页 > 其他 > 详细

行转列的应用

时间:2014-12-26 02:14:14      阅读:304      评论:0      收藏:0      [点我收藏+]
快到圣诞节了,需求弄出了一堆活动
其中一个活动要求用户每天签到,连续若干天,有不同级别的奖励.
签到表模拟如下,userid记录用户的ID,createtime模拟用户签到的时间.


其中nums是数字辅助表,用法参见
http://blog.itpub.net/29254281/viewspace-1362897/

  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;
bubuko.com,布布扣

上面的SQL模拟了一批用户的签到数据.
程序研发都已经做完了,需求拿了一个excel模板,让我统计每天的每小时用户签到情况.
这个应该是行转列的一个典型应用吧

  1. select
  2.     h,
  3.     sum(case when createtime=‘2014-12-15‘ then c else 0 end) 15签到,
  4.     sum(case when createtime=‘2014-12-16‘ then c else 0 end) 16签到,
  5.     sum(case when createtime=‘2014-12-17‘ then c else 0 end) 17签到,
  6.     sum(case when createtime=‘2014-12-18‘ then c else 0 end) 18签到,
  7.     sum(case when createtime=‘2014-12-19‘ then c else 0 end) 19签到,
  8.     sum(case when createtime=‘2014-12-20‘ then c else 0 end) 20签到,
  9.     sum(case when createtime=‘2014-12-21‘ then c else 0 end) 21签到
  10. from
  11. (
  12.     select
  13.         date_format(createtime,‘%Y-%m-%d‘) createtime,
  14.         hour(createtime) h,
  15.         count(*) c
  16.     from award_chance_history
  17.     group by
  18.         date_format(createtime,‘%Y-%m-%d‘),
  19.         hour(createtime)
  20. ) a
  21. group by h with rollup;
bubuko.com,布布扣

一会儿需求又来了,说是中间缺数据啊.没有18点,21点的数据啊.
我解释了半天,说是那几个时间点,没有用户签到.
人家需求不管,说是没有用户签到的时间段,可以补成0.
(最近天天加班,心情不好,当时真想掐死她..)
不过其实也不难.使用数字辅助表就可以了.

  1. select
  2.         h 小时,
  3.         sum(case when createtime=‘2014-12-15‘ then c else 0 end) 15签到,
  4.         sum(case when createtime=‘2014-12-16‘ then c else 0 end) 16签到,
  5.         sum(case when createtime=‘2014-12-17‘ then c else 0 end) 17签到,
  6.         sum(case when createtime=‘2014-12-18‘ then c else 0 end) 18签到,
  7.         sum(case when createtime=‘2014-12-19 then c else 0 end) 19签到,
  8.         sum(case when createtime=‘2014-12-20‘ then c else 0 end) 20签到,
  9.         sum(case when createtime=‘2014-12-21‘ then c else 0 end) 21签到
  10. from
  11. (
  12.      select b.h h,c.createtime,c.c from
  13.      (
  14.         select id-1 h from nums where id<=24
  15.      ) b    
  16.      left join
  17.      (
  18.         select
  19.          date_format(createtime,‘%Y-%m-%d) createtime,
  20.          hour(createtime) h,
  21.          count(*) c
  22.         from award_chance_history
  23.         group by
  24.          date_format(createtime,‘%Y-%m-%d‘),
  25.          hour(createtime)
  26.       ) c on (b.h=c.h)
  27. ) a
  28. group by h with rollup;
bubuko.com,布布扣

好了,没有用户签到的时间段也填充了0

刚做完,新需求又来了,“统计每天的用户签到数据和每天的增量数据”..好吧
通过左连接,求得两天内的签到差值,然后union当天的签到数据,最后再行转列.
他的增量数据是这个意思,比如16日4人签到,17日5人签到,那么17日的增量数据为1.
当然,如果15日的签到人数为5,16日的签到人数为4,那么16日的增量数据为-1.
这个是可能出现负数的.
  1. select
  2.         type 类型,
  3.         sum(case when createtime=‘2014-12-15‘ then c else 0 end) 15签到,
  4.         sum(case when createtime=‘2014-12-16‘ then c else 0 end) 16签到,
  5.         sum(case when createtime=‘2014-12-17‘ then c else 0 end) 17签到,
  6.         sum(case when createtime=‘2014-12-18‘ then c else 0 end) 18签到,
  7.         sum(case when createtime=‘2014-12-19‘ then c else 0 end) 19签到,
  8.         sum(case when createtime=‘2014-12-20‘ then c else 0 end) 20签到,
  9.         sum(case when createtime=‘2014-12-21‘ then c else 0 end) 21签到
  10. from
  11. (
  12.         select b.createtime,ifnull(b.c-c.c,0) c,‘增量‘ type from
  13.         (
  14.             select
  15.              date_format(createtime,‘%Y-%m-%d‘) createtime,
  16.              count(*) c
  17.             from award_chance_history
  18.             group by
  19.              date_format(createtime,‘%Y-%m-%d‘)
  20.         ) b
  21.         left join
  22.         (
  23.             select
  24.              date_format(createtime,‘%Y-%m-%d‘) createtime,
  25.              count(*) c
  26.             from award_chance_history
  27.             group by
  28.              date_format(createtime,‘%Y-%m-%d‘)
  29.         ) c on(b.createtime=c.createtime+ interval 1 day)
  30.     union all
  31.         select
  32.          date_format(createtime,‘%Y-%m-%d‘) createtime,
  33.          count(*) c,
  34.          ‘当前‘
  35.         from award_chance_history
  36.         group by
  37.          date_format(createtime,‘%Y-%m-%d‘)
  38. ) a
  39. group by type 
  40. order by case when type=‘当前‘ then 1 else 0 end desc;
bubuko.com,布布扣

还有新需求,
下面的SQL模拟不同的用户签到了不同的天数
  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;
新的需求是查询签到天数相同的用户数量.
比如,都是签到了一天的用户数量
bubuko.com,布布扣
我这边的数据是,
签到了3天的用户有两人,
签到了4天的用户有四人,
签到了5天的用户有四人..
需求就是统计这个,根据这个数量准备奖品,顺便看一下用户的参与热情.

采用了两次分组的方法.

  1. select
  2.     sum(case when day=1 then cn else 0 end) 1天,
  3.     sum(case when day=2 then cn else 0 end) 2天,
  4.     sum(case when day=3 then cn else 0 end) 3天,
  5.     sum(case when day=4 then cn else 0 end) 4天,
  6.     sum(case when day=5 then cn else 0 end) 5天,
  7.     sum(case when day=6 then cn else 0 end) 6天,
  8.     sum(case when day=7 then cn else 0 end) 7天,
  9.     sum(case when day=8 then cn else 0 end) 8天,
  10.     sum(case when day=9 then cn else 0 end) 9天,
  11.     sum(case when day=10 then cn else 0 end) 10天
  12. from
  13. (
  14.     select c day,count(*) cn
  15.     from
  16.     (
  17.         select userid,count(*) c from award_chance_history group by userid
  18.     ) a
  19.     group by c
  20. ) b
bubuko.com,布布扣

实际的需求,还稍微复杂一些,不过都是上面几个方法的排列组合.
1.使用数字辅助表填充数据
2.使用外连接求差值数据.
3.使用union all 拼接行转列的数据
4.使用两次group by求达到相同条件的汇总数据.

bubuko.com,布布扣

行转列参考:
http://blog.itpub.net/29254281/viewspace-775660/

行转列的应用

原文:http://blog.itpub.net/29254281/viewspace-1379159/

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!