随着前两个月被抓去做原型设计1,接着又被抓去做测试,最近被抓去做数据开发了……
开发过程中遇到了一个小问题,大致场景是:
公司中每个客户都有一个等级,客户等级总会发生变更,这些等级中C(Common)代表普通等级,S(Silver)代表银卡等级,G(Golden)代表金卡等级,P(Platinum)代表铂金卡等级,等级顺序依次是C<S<G<P,求每个客户连续不低于银卡等级的时间、连续不低于金卡等级的时间、连续不低于铂金卡等级的时间?
list_id | customer_id | old_level | new_level | insert_time |
---|---|---|---|---|
1 | 123456 | C | S | 2010/10/14 01:11:51 |
2 | 123456 | S | G | 2011/02/19 08:47:49 |
3 | 123456 | G | C | 2014/11/11 11:45:36 |
4 | 123456 | C | S | 2015/11/11 10:55:01 |
5 | 123456 | S | G | 2016/11/11 09:55:32 |
6 | 123456 | G | P | 2019/11/11 12:11:11 |
上面这个表格中的数据是我瞎编的一个例子,客户ID为123456的这位客户在2010年成为银卡客户,在2011年升级为金卡客户,又在2014年降级成为普通客户,随后又在2015年重新升级为银卡客户,其后客户等级保持连续不低于银卡等级,所以该客户连续不低于银卡等级的时间是2015/11/11
。
这个小问题是要在ORACLE中写SQL解决。最开始我困在“连续”这个词中,解题思路想得极其复杂,寻思着把代表等级的C/S/G/P等字母替换成可以直接比较大小的数字,每个客户按等级变更的时间顺序排序,然后把排序得到的序号作为父节点去用递归函数写条件依次判断……哈哈,我自己也觉得这个问题被我想复杂了,所以当时也没有直接按原来的思路去做,而是先放着干别的去了。过了两天,在把一些贼难、贼麻烦、贼耗时间的问题弄得差不多以后,才回过头来再处理这个问题。
可是我还是想不到简单解法,于是就把这个问题拿去问了同事小花,小花给了我一个很简单的思路:把“不连续”的变更记录直接去掉,然后对时间取最小值。
select t.customer_id, min(ch.insert_time)
from t_base t --确定数据范围的基础表,瞎编的表名
left join t_vip_change ch on t.customer_id = ch.customer_id --t_vip_change也是瞎编的表名
where ch.new_level in ('S', 'G', 'P')
and not exists (select '1'
from t_vip_change ch2
where ch2.customer_id = ch.customer_id
and ch2.new_level not in ('S', 'G', 'P')
and ch2.insert_time > ch.insert_time)
group by t.customer_id;
小花说正是因为她本来就不会递归那些东西,所以解题思路才倾向于越简单越好,而我正是因为会那些复杂方法,才会想得太复杂。正所谓,乱花渐欲迷人眼2,浅草才能没马蹄。