|
前面说了。按这种写法,至少要union all七八个子句。且不说容易出错,万一某天,甲方爸爸说,我今天不想看1月1日的数据,我想看1月8日开始的留存率。。。。估计这时候你就一波操作猛如虎,“查找,替换。”先把1月1日的改成1月8日,然后把1月2日的改成1月9日……如此类推。过几天,甲方爸爸又说,我想看1月3日一个星期内的留存率。。。。于是你心里一万匹草泥马奔腾而过,腹诽不已,“这特么还有完没完啊?”,但你不敢声张,只好脸上笑嘻嘻,心里MMP。
经过几番折腾,你决定用变量来处理。
- declare @day0 date
- declare @day1 date
- declare @day2 date
- declare @day3 date
- declare @day4 date
- declare @day5 date
- declare @day6 date
- declare @day7 date
- declare @day8 date
- set @day0='2019-1-1'
- set @day1=DATEADD(day,1,@day0)
- set @day2=DATEADD(day,2,@day0)
- set @day3=DATEADD(day,3,@day0)
- set @day4=DATEADD(day,4,@day0)
- set @day5=DATEADD(day,5,@day0)
- set @day6=DATEADD(day,6,@day0)
- set @day7=DATEADD(day,7,@day0)
- set @day8=DATEADD(day,8,@day0)
- select 登录时间
- ,SUM(day0) as day0
- ,SUM(day1) as day1
- ,SUM(day2) as day2
- ,SUM(day3) as day3
- ,SUM(day4) as day4
- ,SUM(day5) as day5
- ,SUM(day6) as day6
- ,SUM(day7) as day7
- ,SUM(day8) as day8
- from(
- select @day0 as 登录时间
- ,count(distinct case when a.登录时间=@day0 then a.用户ID else null end) as day0
- ,count(distinct case when a.登录时间=@day1 then a.用户ID else null end) as day1
- ,count(distinct case when a.登录时间=@day2 then a.用户ID else null end) as day2
- ,count(distinct case when a.登录时间=@day3 then a.用户ID else null end) as day3
- ,count(distinct case when a.登录时间=@day4 then a.用户ID else null end) as day4
- ,count(distinct case when a.登录时间=@day5 then a.用户ID else null end) as day5
- ,count(distinct case when a.登录时间=@day6 then a.用户ID else null end) as day6
- ,count(distinct case when a.登录时间=@day7 then a.用户ID else null end) as day7
- ,count(distinct case when a.登录时间=@day8 then a.用户ID else null end) as day8
- from log_info a,(select distinct 用户ID from log_info where 登录时间=@day0) b
- where a.用户ID=b.用户ID and a.登录时间>=@day0
- group by a.登录时间
- union all
- select @day1 as 登录时间
- ,0 as day0
- ,count(distinct case when a.登录时间=@day1 then a.用户ID else null end) as day1
- ,count(distinct case when a.登录时间=@day2 then a.用户ID else null end) as day2
- ,count(distinct case when a.登录时间=@day3 then a.用户ID else null end) as day3
- ,count(distinct case when a.登录时间=@day4 then a.用户ID else null end) as day4
- ,count(distinct case when a.登录时间=@day5 then a.用户ID else null end) as day5
- ,count(distinct case when a.登录时间=@day6 then a.用户ID else null end) as day6
- ,count(distinct case when a.登录时间=@day7 then a.用户ID else null end) as day7
- ,count(distinct case when a.登录时间=@day8 then a.用户ID else null end) as day8
- from log_info a,(select distinct 用户ID from log_info where 登录时间=@day1) b
- where a.用户ID=b.用户ID
- --新用户
- and a.用户ID not in(select 用户ID from log_info c where c.登录时间=@day0)
- group by a.登录时间
- /*
- 这里仅用2个表进行union all
- 以下从略。
- union all
- …………
- */
- ) a
- group by 登录时间
复制代码 这时候,你发现,只需要改下@day0的值,就能随时算出留存客户数了。你开始为自己的聪明鼓掌。但你还是隐隐有些担忧。现在甲方爸爸只是想看一个星期的数据,你已经写得这么复杂了,万一某天他心血来潮要看一个月的呢?此外,还有一个问题,数据都不是现成的。每次修改条件,就必须重新计算。你觉得这可能会影响体验。那么,这个是否可以做成一张表,每次运行时把数据插入再展示呢?
于是,你开始在论坛里翻到了roych写的那篇帖子,终于体会到宽表的好处了。那么表结构该怎么确定呢?是不是可以按结果表那样做?如果按那样建表的话,那么主键显然不好确定。用第一列的日期作为主键看起来没什么问题,
但实际上,你会发现,这个根本就不具备主键的气质。这个字段来源于一个常量。——虽然看起来像是变量,但到了底层,它每一行都是一样的。——如果真的采取这样的方案,有没有问题?
当然没有问题。前面我们不用存储过程都能写出来,何况现在改为存储过程,理论上应该更简单才对。但由于不存在主键或者唯一索引的要求,因此,原先的SQL语句也就谈不上优化了。
那么为了优化SQL语句,这宽表应该怎么建呢?欲知后事如何,且看下回分解。
|
|