Pseudocode

手撸RPT层代码.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
-- RPT 层搭建

Step1:销售主题统计宽表
需求一:门店月销售单量排行, 按月统计,各个门店的 月销售单量

time_type 的取值有 year, month, week, date,
group_type 的取值有 city_id,tread_area_id,store_id,brand_id,max_class_id,mid_class_id,min_class_id.
-- 共有28中分组类型

-- 建表(是在hive中创建的)
create table yp_rpt.rpt_sale_store_cnt_month(
date_time string,-- 统计日期
year_code string, -- 年code
year_month string, -- 年月
-- 城市商圈店铺,id + name 共6个字段
-- 店铺成交单量,小程序,安卓,ios,pcweb店铺成交单量
order_store_cnt bigint,miniapp_order_store_cnt,android_order_store_cnt,.......
)row format delimited fields terminated by '\t'
stored as orc tblproperties('orc.compress'='snappy');

-- 向表中插入数据(最终要的就是知道按月,和店铺来统计销售单量,从而group_type和time_type取值注意)
insert into
select
'2023-06-05' as date_time,
year_code,
year_month,
city_id,city_name,tread_area_id,tread_area_name,store_id,store_name,
order_cnt,miniapp_order_store_cnt.....
from yp_dm.dm_sale
where group_type='store_id' and time_type='month' and store_id is not null;


Step2:
需求2: 按天统计 总销售额 和 销售单量 rpt_sale_day

-- 建表
CREATE TABLE yp_rpt.rpt_sale_day(
date_time string COMMENT '统计日期,不能用来分组统计',
year_code string COMMENT '年code',
month_code string COMMENT '月份编码',
day_month_num string COMMENT '一月第几天',
dim_date_id string COMMENT '日期',

sale_amt DECIMAL(38,2) COMMENT '销售收入',
order_cnt BIGINT COMMENT '成交单量'
)
COMMENT '日销售曲线'
ROW format delimited fields terminated BY '\t'
stored AS orc tblproperties ('orc.compress' = 'SNAPPY');

-- 向表中插入数据(Presto中实现
insert into yp_rpt.rpt_sale_day
select
-- time_type, group_type,
'2023-06-05' as date_time,
year_code,
month_code,
day_month_num,
dim_date_id,
sale_amt,
order_cnt
from
yp_dm.dm_sale
where time_type='date' and group_type='all'

Step3:需求3: 渠道销售占比
-- 比如每天不同渠道的订单量占比.小程序成交单量 / 总订单量,安卓成交单量 / 总订单量...

-- 建表
create teble yp_rpt.rpt_sale_fromtype_ration(
-- 统计日期,统计时间维度,年code,年月,日期
-- 成交单量,小程序成交单量,小程序成交量占比,安卓订单量,安卓订单量占比.
)comment '渠道销售占比'
row format delimited fields terminated by '\t'
stored as orc tblproperties ('orc.compress'='snappy');

-- 向表中插入数据
insert into rpt_sale_fromtype_ratio
select
'2023-06-05' as date_time,
time_type,
year_code,year_month,dim_date_id,order_cnt,miniapp_order_cnt
cast(miniapp_order_cnt as decimal(38,2))/cast(order_cnt as decimal(38,2)) * 100,
cast(miniapp_order_cnt as decimal(38,2))/cast(order_cnt as decimal(38,2)) * 100,
from yp_dm.dm_sale
where group_type='all'


-- 需求一:商品销量topN, 统计出某天销量最多的top10商品(销量最多,这里是按支付件数计算payment_num
-- 需求二:商品收藏topN, 统计出某天收藏量最多的top10商品
-- 需求三:商品加入购物车topN, 统计出某天,购物车最多的top10商品
-- 需求四: 商品退款率TOPN, 统计出某天,退款率最多的top10商品.

-- 需求一
insert into hive.yp_rpt.rpt_goods_sale_topN
with tmp as (
select
dt,
sku_id,payment_num,
dense_rank() over(order by payment_num desc) rn
from yp_dm.dm_sku
)
select dt,sku_id,payment_num where rn<=10; -- 因为dm层已经是日统计宽表了,且已经按照商品分类,所以不用分组

-- 需求二:商品收藏topN
insert into hive.yp_rpt.rpt_goods_favor_topN
with t1 as (
select
dt,
sku_id,
favor_count,
rank() over(order by favor_count desc) rn
from yp_dws.dws_sku_daycount
)
select dt,sku_id,favor_count where rn<=10;

-- 需求三:商品加入购物车topN
insert into yp_rpt.rpt_goods_cart_topN
select '2023-06-05',sku_id,cart_num from yp_dws.dws_sku_daycount
order by cart_num desc limit 10;

-- 需求四: 商品退款率TOPN(由于退款比较少,我们换成近30天的退款率
select
'2023-06-04' as dt,
sku_id,
cast(退款订单个数统计 as decimal(38,2))/cast(支付订单数 as decimal(38,2)) * 100
from yp_dm.dm_sku
where payment_num > 0 -- 只有支付过才能计算退款
order by refund_ratio desc
limit 10;

-- 用户主题统计宽表
-- 活跃会员数: login_date_last, 最后一次登录时间是昨天的, 即为: 活跃会员.
-- 新增会员数: login_date_first, 首次登录时间是昨天的, 即为: 新增会员.
-- 新增消费会员数: payment_date_first, 首次支付时间是昨天的, 即为: 新增消费会员.
-- 总付费会员数: payment_count, 累计支付次数 > 0
-- 总会员数: user_id, 用户id, 有几个, 就有几个会员.
-- 会员活跃率: 活跃会员数 / 总会员数
-- 总会员付费率: 总付费会员数 / 总会员数
-- 会员新鲜度: 新增会员数 / 活跃会员数, 指的是: 昨日登录用户中, 新增会员占比
select
'2023-06-04' as dt,
sum(if(昨日登录时间='2023-06-04', 1, 0)) as 活跃会员数,
sum(if(首次登录时间='2023-06-04', 1, 0)) as 新增会员数
sum(if(首次支付时间='2023-06-04', 1, 0)) as 新增消费会员数
sum(if(支付订单数>0, 1, 0)) as 总付费会员数
count(*) as 总会员数
-- 会员活跃率
cast(
if(
sum(if(昨日登录时间='2023-06-04', 1, 0)) =0
null,
sum(if(昨日登录时间='2023-06-04', 1, 0))/count(*) * 100
)
as decimal(38,2)
) as as 会员活跃率
......
from yp_dm.dm_user;

-- 上面的方式虽然无脑,但是写的比较多(可以用cte表达式替代
with temp as (
select
'2023-06-04' as dt,
sum(if(昨日登录时间='2023-06-04', 1, 0)) as 活跃会员数,
sum(if(首次登录时间='2023-06-04', 1, 0)) as 新增会员数
sum(if(首次支付时间='2023-06-04', 1, 0)) as 新增消费会员数
sum(if(支付订单数>0, 1, 0)) as 总付费会员数
count(*) as 总会员数
from yp_dm.dm_user
)
select
*,
cast(活跃会员数 as decimal)/cast(总会员数 as decimal) * 100 as 会员活跃率,
总付费会员数 / 总会员数 -- 改造只需要加上cast,然后还有*100 最后同上
新增会员数 / 活跃会员数
from temp;

Code_Details

需求1: 门店月销售单量排行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use yp_rpt;
-- 1. 建表, Hive实现.

-- 2. 插入表数据. Presto实现.
insert into hive.yp_rpt.rpt_sale_store_cnt_month
select
'2023-06-05' date_time,
year_code,
year_month,
city_id,
city_name,
trade_area_id,
trade_area_name,
store_id,
store_name,
order_cnt,
miniapp_order_cnt,
android_order_cnt,
ios_order_cnt,
pcweb_order_cnt
from yp_dm.dm_sale
where time_type='month' and group_type='store' and store_id is not null; -- 月 + 门店(日期 + 城市 + 商圈 + 店铺), 店铺id不为null

-- 3. 查询表数据. Presto实现.
select * from yp_rpt.rpt_sale_store_cnt_month;

需求2:按天统计 总销售额 和 销售单量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 1. 建表, Hive实现.
--日销售曲线

-- 2. 插入表数据. Presto实现.
insert into yp_rpt.rpt_sale_day
select
-- time_type, group_type,
'2023-06-05' as date_time,
year_code,
month_code,
day_month_num,
dim_date_id,
sale_amt,
order_cnt
from
yp_dm.dm_sale
where time_type='date' and group_type='all'

-- 3. 查询表数据. Presto实现.
select * from yp_rpt.rpt_sale_day;

需求3: 渠道销售占比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
-- 1. 建表, Hive实现.   渠道销量占比

-- 2. 插入表数据. Presto实现.
insert into hive.yp_rpt.rpt_sale_fromtype_ratio
select
'2023-06-05' as date_time,
time_type,
year_code,
year_month,
dim_date_id,
order_cnt, -- 总订单量
miniapp_order_cnt, -- 小程序成交单量.
cast(
-- 小程序成交单量 转成 小数 / 总订单量 转成 小数
cast(miniapp_order_cnt as decimal(38, 2)) / cast(order_cnt as decimal(38, 2)) * 100 as decimal(5, 2)
) as miniapp_order_ratio,

android_order_cnt, -- 安卓成交单量.
cast(
-- 安卓成交单量 转成 小数 / 总订单量 转成 小数
cast(android_order_cnt as decimal(38, 2)) / cast(order_cnt as decimal(38, 2)) * 100 as decimal(5, 2)
) as android_order_ratio,

ios_order_cnt, -- 苹果成交单量.
cast(
-- 苹果成交单量 转成 小数 / 总订单量 转成 小数
cast(ios_order_cnt as decimal(38, 2)) / cast(order_cnt as decimal(38, 2)) * 100 as decimal(5, 2)
) as ios_order_ratio,

pcweb_order_cnt, -- pcWeb, 成交单量.
cast
-- 苹果成交单量 转成 小数 / 总订单量 转成 小数
cast(pcweb_order_cnt as decimal(38, 2)) / cast(order_cnt as decimal(38, 2)) * 100 as decimal(5, 2)
) as pcweb_order_ratio
from
yp_dm.dm_sale
where group_type='all' -- and time_type='date' 统计每天的 不同渠道销售占比.
;

-- 演示如何获取 小数形式的占比.
select cast(10 / 3 as decimal(5, 2)); -- 3
select 10.0 / 3; -- 3.3

-- 3. 查询表数据. Presto实现.
select * from yp_rpt.rpt_sale_fromtype_ratio;

商品主题统计宽表

需求一:商品销量==topN==, 统计出某天销量最多的top10商品
需求二:商品收藏==topN==, 统计出某天收藏量最多的top10商品
需求三:商品加入购物车==topN==, 统计出某天,购物车最多的top10商品
需求四: 商品退款率TOPN, 统计出某天,退款率最多的top10商品.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
-- 1. 建表, Hive实现.

-- 2. 插入表数据. Presto实现.
-- 需求一:商品销量==topN==, 统计出某天销量最多的top10商品
-- 思路1: 简单粗暴, order by + limit n
select dt, sku_id, payment_num from yp_dws.dws_sku_daycount order by payment_num desc limit 10;

-- 如下的这个SQL, 才是我们要的SQL, 即: 统计出某天的销量最多的商品, 但是目前我们的数据都是模拟数据, 可能会出现某天没有数据的情况.
-- 因此, 我们改造下SQL, 即: 不写where条件筛选日期了, 改为在所有商品中找, 销量最多的Top10的商品, 但是实际开发中, 你要加上时间过滤.
select dt, sku_id, payment_num from yp_dws.dws_sku_daycount where dt ='2021-08-31' order by payment_num desc;

-- 思路2: 窗口函数.
insert into hive.yp_rpt.rpt_goods_sale_topN
with t1 as (
select
dt, sku_id, payment_num,
dense_rank() over(order by payment_num desc) dr
from yp_dws.dws_sku_daycount
)
select '2023-06-04', sku_id, payment_num from t1 where dr <= 10;
-- where dt='2021-08-31' 这里不写, 因为写了可能没有数据.

-- 需求二:商品收藏==topN==, 统计出某天收藏量最多的top10商品
-- 思路1: order by + limit n
select dt, sku_id, favor_count from yp_dws.dws_sku_daycount
-- where dt ='某天'
order by favor_count desc limit 10;

-- 思路2: 窗口函数, 求 TopN
insert into hive.yp_rpt.rpt_goods_favor_topN
with t1 as (
select
dt, sku_id, favor_count,
rank() over(order by favor_count desc) rk
from yp_dws.dws_sku_daycount
-- where dt ='某天'
)
select '2023-06-04', sku_id, favor_count from t1 where rk <= 10;

-- 需求三:商品加入购物车==topN==, 统计出某天,购物车最多的top10商品
insert into yp_rpt.rpt_goods_cart_topN
select '2023-06-04', sku_id, cart_num from yp_dws.dws_sku_daycount
-- where dt = '某天'
order by cart_num desc limit 10;

-- 需求四: 商品退款率TOPN, 统计出某天,退款率最多的top10商品.
-- 当数据合法时, 应该用如下的操作来计算, 即: dws层的 商品主题日统计宽表, 但是我们是模拟数据, 所以这里我们从 dm层 商品统计宽表中, 找 近30天累计值来算.
-- 即: 题设是计算某天退款率最多商品, 我们改为: 近30天, 退款率最多商品.
-- select dt, refund_count, payment_count from yp_dws.dws_sku_daycount where refund_count > 0;
insert into hive.yp_rpt.rpt_goods_refund_topN
select
'2023-06-04' as dt,
sku_id,
cast(
cast(refund_last_30d_count as decimal(38, 4)) / payment_last_30d_count * 100
as decimal(5, 2)
) as refund_ratio
from yp_dm.dm_sku
where payment_last_30d_count > 0 -- 支付次数 > 0, 说明有买过, 买过才可以退款.
order by refund_ratio desc
limit 10;

-- 3. 查询表数据. Presto实现.
-- 需求一:商品销量==topN==, 统计出某天销量最多的top10商品
select * from yp_rpt.rpt_goods_sale_topN;
-- 需求二:商品收藏==topN==, 统计出某天收藏量最多的top10商品
select * from yp_rpt.rpt_goods_favor_topN;
-- 需求三:商品加入购物车==topN==, 统计出某天,购物车最多的top10商品
select * from yp_rpt.rpt_goods_cart_topN;

-- 需求四: 商品退款率TOPN, 统计出某天,退款率最多的top10商品.
select * from yp_rpt.rpt_goods_refund_topN;

用户主题统计宽表

​ 活跃会员数: login_date_last, 最后一次登录时间是昨天的, 即为: 活跃会员.
​ 新增会员数: login_date_first, 首次登录时间是昨天的, 即为: 新增会员.
​ 新增消费会员数: payment_date_first, 首次支付时间是昨天的, 即为: 新增消费会员.
​ 总付费会员数: payment_count, 累计支付次数 > 0
​ 总会员数: user_id, 用户id, 有几个, 就有几个会员.
​ 会员活跃率: 活跃会员数 / 总会员数
​ 总会员付费率: 总付费会员数 / 总会员数
​ 会员新鲜度: 新增会员数 / 活跃会员数, 指的是: 昨日登录用户中, 新增会员占比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
-- 1. 建表, Hive实现.

-- 2. 插入表数据. Presto实现.
-- 思路1: 直接1个查询搞定, 但是涉及到 计算的时候, 可能会有重复计算, 甚至小括号过多, 容易写错.
select
'2023-06-04' as dt, -- 统计时间, 昨天.
sum(if(login_date_last='2023-06-04', 1, 0)) day_users, -- 活跃会员数
sum(if(login_date_first='2023-06-04', 1, 0)) day_new_users, -- 新增会员数
sum(if(payment_date_first='2023-06-04', 1, 0)) day_new_payment_users, -- 新增消费会员数
sum(if(payment_count > 0, 1, 0)) payment_users, -- 总付费会员数
count(*) users, -- 总会员数
cast(
if(
sum(if(login_date_last='2023-06-04', 1, 0)) = 0,
null,
sum(if(login_date_last='2023-06-04', 1, 0)) / count(*) * 100
)
as decimal(5, 2)) day_users2users, -- 会员活跃率: 活跃会员数 / 总会员数
payment_users2users, -- 总会员付费率: 总付费会员数 / 总会员数
day_new_users2users -- 新增会员数 / 活跃会员数
from yp_dm.dm_user;

-- 思路2: CTE表达式实现.
insert into hive.yp_rpt.rpt_user_count
with tmp as (
select
'2023-06-05' as dt, -- 统计时间
sum(if(login_date_last='2023-06-04', 1, 0)) day_users, -- 活跃会员数
sum(if(login_date_first='2023-06-04', 1, 0)) day_new_users, -- 新增会员数
sum(if(payment_date_first='2023-06-04', 1, 0)) day_new_payment_users, -- 新增消费会员数
sum(if(payment_count > 0, 1, 0)) payment_users, -- 总付费会员数
count(*) users -- 总会员数
from yp_dm.dm_user
)
select
*,
cast(
if(
day_users = 0, -- 活跃会员数 为 0
null,
cast(day_users as decimal(38, 4)) / users * 100 -- 活跃会员数不为0, 则 计算 占比.
) as decimal(5, 2)
) day_users2users, -- 会员活跃率: 活跃会员数 / 总会员数
cast(
if(
payment_users = 0, -- 总付费会员数 为 0
null,
cast(payment_users as decimal(38, 4)) / users * 100 -- 总付费会员数 不为0, 则 计算 占比.
) as decimal(5, 2)
) payment_users2users, -- 总会员付费率: 总付费会员数 / 总会员数
cast(
if(
day_new_users = 0, -- 新增会员数 为 0
null,
cast(day_new_users as decimal(38, 4)) / day_users * 100 -- 新增会员数 不为0, 则 计算 占比.
) as decimal(5, 2)
) day_new_users2users -- 新增会员数 / 活跃会员数
from tmp;

-- 3. 查询表数据. Presto实现.
select * from yp_rpt.rpt_user_count;


Presto把Hive的数据 导出到 MySQL中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 1. 修改Hadoop01, Hadoop02两台机器的 Presto 配置文件.
-- 2. 重启Presto服务, 在CRT中完成.

-- 3. 创建MySQL的数据库 和 数据表.
-- 创建数据库, 注意: 去 MySQL中执行.
CREATE DATABASE yp_olap DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
use yp_olap;

-- 4. Presto实现, 把Hive的(RPT数据) 导出到 MySQL中.
insert into mysql.yp_olap.rpt_goods_cart_topn
select * from hive.yp_rpt.rpt_goods_cart_topn;

-- 5. 通过BI展示 MySQL中的 分析后的数据.
select * from mysql.yp_olap.rpt_goods_cart_topn;