数仓常见sql套路

业务术语
1)用户
用户以设备为判断标准,在移动统计中,每个独立设备认为是一个独立用户。Android
系统根据IMEI 号,IOS 系统根据OpenUDID 来标识一个独立用户,每部手机一个用户。
2)新增用户
首次联网使用应用的用户。如果一个用户首次打开某APP,那这个用户定义为新增用
户;卸载再安装的设备,不会被算作一次新增。新增用户包括日新增用户、周新增用户、月
新增用户。
3)活跃用户
打开应用的用户即为活跃用户,不考虑用户的使用情况。每天一台设备打开多次会被计
为一个活跃用户。
4)周(月)活跃用户
某个自然周(月)内启动过应用的用户,该周(月)内的多次启动只记一个活跃用户。
5)月活跃率
月活跃用户与截止到该月累计的用户总和之间的比例。
6)沉默用户
用户仅在安装当天(次日)启动一次,后续时间无再启动行为。该指标可以反映新增用
户质量和用户与APP 的匹配程度。
7)版本分布
不同版本的周内各天新增用户数,活跃用户数和启动次数。利于判断APP 各个版本之
间的优劣和用户行为习惯。
8)本周回流用户
上周未启动过应用,本周启动了应用的用户。
9)连续n 周活跃用户
连续n 周,每周至少启动一次。
10)忠诚用户
连续活跃5 周以上的用户
11)连续活跃用户
连续2 周及以上活跃的用户
12)近期流失用户
连续n(2<= n <= 4)周没有启动应用的用户。(第n+1 周没有启动过)
13)留存用户
某段时间内的新增用户,经过一段时间后,仍然使用应用的被认作是留存用户;这部分
用户占当时新增用户的比例即是留存率。
例如,5 月份新增用户200,这200 人在6 月份启动过应用的有100 人,7 月份启动过
应用的有80 人,8 月份启动过应用的有50 人;则5 月份新增用户一个月后的留存率是50%,
二个月后的留存率是40%,三个月后的留存率是25%。
14)用户新鲜度
每天启动应用的新老用户比例,即新增用户数占活跃用户数的比例。
15)单次使用时长
每次启动使用的时间长度。
16)日使用时长
累计一天内的使用时间长度。
17)启动次数计算标准
IOS 平台应用退到后台就算一次独立的启动;Android 平台我们规定,两次启动之间的
间隔小于30 秒,被计算一次启动。用户在使用过程中,若因收发短信或接电话等退出应用
30 秒又再次返回应用中,那这两次行为应该是延续而非独立的,所以可以被算作一次使用
行为,即一次启动。业内大多使用30 秒这个标准,但用户还是可以自定义此时间间隔。

ods: 原始json数据

dwd:用户启动表数据 get_json_object转换

dwd: dwd_start_log: 
CREATE EXTERNAL TABLE dwd_start_log(
`mid_id` string,
`user_id` string,
`version_code` string,
`version_name` string,
`lang` string,
`source` string,
`os` string,
`area` string,
`model` string,
`brand` string,
`sdk_version` string,
`gmail` string,
`height_width` string,
`app_time` string,
`network` string,
`lng` string,
`lat` string,
`entry` string,
`open_ad_type` string,
`action` string,
`loading_time` string,
`detail` string,
`extend1` string
) PARTITIONED BY (
dt string)
stored as parquet
location '/warehouse/gmall/dwd/dwd_start_log/'
TBLPROPERTIES('parquet.compression'='lzo'); 

dws: 每日设备行为 每日设备行为,主要按照设备id 统计。

create external table dws_uv_detail_daycount
(
`mid_id` string COMMENT '设备唯一标识',
`user_id` string COMMENT '用户标识',
`version_code` string COMMENT '程序版本号',
`version_name` string COMMENT '程序版本名',
`lang` string COMMENT '系统语言',
`source` string COMMENT '渠道号',
`os` string COMMENT '安卓系统版本',
`area` string COMMENT '区域',
`model` string COMMENT '手机型号',
`brand` string COMMENT '手机品牌',
`sdk_version` string COMMENT 'sdkVersion',
`gmail` string COMMENT 'gmail',
`height_width` string COMMENT '屏幕宽高',
`app_time` string COMMENT '客户端日志产生时的时间',
`network` string COMMENT '网络模式',
`lng` string COMMENT '经度',
`lat` string COMMENT '纬度',
`login_count` bigint COMMENT '活跃次数'
) partitioned by(dt string)
stored as parquet
location '/warehouse/gmall/dws/dws_uv_detail_daycount';

2)数据装载
insert overwrite table dws_uv_detail_daycount partition(dt='2020-03-10')
select
mid_id,
concat_ws('|', collect_set(user_id)) user_id,
concat_ws('|', collect_set(version_code)) version_code,
concat_ws('|', collect_set(version_name)) version_name,
concat_ws('|', collect_set(lang))lang,
concat_ws('|', collect_set(source)) source,
concat_ws('|', collect_set(os)) os,
concat_ws('|', collect_set(area)) area,
concat_ws('|', collect_set(model)) model,
concat_ws('|', collect_set(brand)) brand,
concat_ws('|', collect_set(sdk_version)) sdk_version,
concat_ws('|', collect_set(gmail)) gmail,
concat_ws('|', collect_set(height_width)) height_width,
concat_ws('|', collect_set(app_time)) app_time,
concat_ws('|', collect_set(network)) network,
concat_ws('|', collect_set(lng)) lng,
concat_ws('|', collect_set(lat)) lat,
count(*) login_count
from dwd_start_log
where dt='2020-03-10'
group by mid_id;

dwt: 设备主题宽表

新旧数据合并

create external table dwt_uv_topic
(
`mid_id` string COMMENT '设备唯一标识',
`user_id` string COMMENT '用户标识',
`version_code` string COMMENT '程序版本号',
`version_name` string COMMENT '程序版本名',
`lang` string COMMENT '系统语言',
`source` string COMMENT '渠道号',
`os` string COMMENT '安卓系统版本',
`area` string COMMENT '区域',
`model` string COMMENT '手机型号',
`brand` string COMMENT '手机品牌',
`sdk_version` string COMMENT 'sdkVersion',
`gmail` string COMMENT 'gmail',
`height_width` string COMMENT '屏幕宽高',
`app_time` string COMMENT '客户端日志产生时的时间',
`network` string COMMENT '网络模式',
`lng` string COMMENT '经度',
`lat` string COMMENT '纬度',
`login_date_first` string comment '首次活跃时间',
`login_date_last` string comment '末次活跃时间',
`login_day_count` bigint comment '当日活跃次数',
`login_count` bigint comment '累积活跃天数'
) stored as parquet
location '/warehouse/gmall/dwt/dwt_uv_topic';

--sql-- full outer join 与 if 判断 join字段是否为空  
insert overwrite table dwt_uv_topic
select
	nvl(new.mid_id,old.mid_id),
	nvl(new.user_id,old.user_id),
	nvl(new.version_code,old.version_code),
	nvl(new.version_name,old.version_name),
	nvl(new.lang,old.lang),
	nvl(new.source,old.source),
	nvl(new.os,old.os),
	nvl(new.area,old.area),
	nvl(new.model,old.model),
	nvl(new.brand,old.brand),
	nvl(new.sdk_version,old.sdk_version),
	nvl(new.gmail,old.gmail),
	nvl(new.height_width,old.height_width),
	nvl(new.app_time,old.app_time),
	nvl(new.network,old.network),
	nvl(new.lng,old.lng),
	nvl(new.lat,old.lat),
	if(old.mid_id is null,'2020-03-10',old.login_date_first),
	if(new.mid_id is not null,'2020-03-10',old.login_date_last),
	if(new.mid_id is not null, new.login_count,0),
	nvl(old.login_count,0)+if(new.login_count>0,1,0)
from
(
select
   *
from dwt_uv_topic
)old
full outer join
(
select
	*
from dws_uv_detail_daycount
where dt='2020-03-10'
)new
on old.mid_id=new.mid_id;

join 图示
在这里插入图片描述

ads: 设备主题

1、活跃设备数(日、周、月)

create external table ads_uv_count(
`dt` string COMMENT '统计日期',
`day_count` bigint COMMENT '当日用户数量',
`wk_count` bigint COMMENT '当周用户数量',
`mn_count` bigint COMMENT '当月用户数量',
`is_weekend` string COMMENT 'Y,N 是否是周末,用于得到本周最终结果',
`is_monthend` string COMMENT 'Y,N 是否是月末,用于得到本月最终结果'
) COMMENT '活跃设备数'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_uv_count/';

-- 日活
select
	'2020-03-10' dt,
	count(*) ct
from dwt_uv_topic
where login_date_last='2020-03-10'

-- 周活
select
	'2020-03-10' dt,
	count (*) ct
from dwt_uv_topic
where login_date_last>=date_add(next_day('2020-03-10','MO'),-7)

-- 月活
select
	'2020-03-10' dt,
	count (*) ct
from dwt_uv_topic
where date_format(login_date_last,'yyyy-MM')=date_format('2020-03-10','yyyy-MM')

-- 整合
insert into table ads_uv_count
select
	'2020-03-10' dt,
	daycount.ct,
	wkcount.ct,
	mncount.ct,
	if(date_add(next_day('2020-03-10','MO'),-1)='2020-03-10','Y','N') ,
	if(last_day('2020-03-10')='2020-03-10','Y','N')
from
(
select
	'2020-03-10' dt,
	count(*) ct
from dwt_uv_topic
where login_date_last='2020-03-10'
)daycount join
(
select
	'2020-03-10' dt,
	count (*) ct
from dwt_uv_topic
where login_date_last>=date_add(next_day('2020-03-10','MO'),-7)
and login_date_last<= date_add(next_day('2020-03-10','MO'),-1)
) wkcount on daycount.dt=wkcount.dt
join
(
select
	'2020-03-10' dt,
	count (*) ct
from dwt_uv_topic
where
date_format(login_date_last,'yyyy-MM')=date_format('2020-03-10','yyyy-MM')
)mncount on daycount.dt=mncount.dt;

2、每日新增设备

drop table if exists ads_new_mid_count;
create external table ads_new_mid_count
(
`create_date` string comment '创建时间' ,
`new_mid_count` BIGINT comment '新增设备数量'
) COMMENT '每日新增设备信息数量'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_new_mid_count/';

insert into table ads_new_mid_count
select
login_date_first,
count(*)
from dwt_uv_topic
where login_date_first='2020-03-10'
group by login_date_first;

3、沉默用户数 : 只在安装当天启动过,且启动时间是在7 天前

create external table ads_silent_count(
`dt` string COMMENT '统计日期',
`silent_count` bigint COMMENT '沉默设备数'
) row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_silent_count';

insert into table ads_silent_count
select
'2020-03-15',
count(*)
from dwt_uv_topic
where login_date_first=login_date_last   -- 第一次启动时间和最后一次启动时间相等
and login_date_last<=date_add('2020-03-15',-7);

4、本周回流用户数 : 上周未活跃,本周活跃的设备,且不是本周新增设备

create external table ads_back_count(
`dt` string COMMENT '统计日期',
`wk_dt` string COMMENT '统计日期所在周',
`wastage_count` bigint COMMENT '回流设备数'
) row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_back_count';

insert into table ads_back_count
select
	'2020-03-15',
	count(*)
from
(
select
     mid_id
from dwt_uv_topic
where login_date_last>=date_add(next_day('2020-03-15','MO'),-7)
and login_date_last<= date_add(next_day('2020-03-15','MO'),-1)
and login_date_first<date_add(next_day('2020-03-15','MO'),-7)
)current_wk
left join
(
select
   mid_id
from dws_uv_detail_daycount
where dt>=date_add(next_day('2020-03-15','MO'),-7*2)
and dt<= date_add(next_day('2020-03-15','MO'),-7-1)
group by mid_id
)last_wk
on current_wk.mid_id=last_wk.mid_id
where last_wk.mid_id is null;

5、流失用户数 : 最近7 天未活跃的设备

select
	'2020-03-20',
	count(*)
from
(
	select
		mid_id
	from dwt_uv_topic
	where login_date_last<=date_add('2020-03-20',-7)
	group by mid_id
)t1;

6、留存率

 某段时间内的新增用户,经过一段时间后,仍然使用应用的被认作是留存用户;

这部分用户占当时新增用户的比例即是留存率。
例如,5 月份新增用户200,这200 人在6 月份启动过应用的有100 人,7 月份启动过
应用的有80 人,8 月份启动过应用的有50 人;则5 月份新增用户一个月后的留存率是50%,
二个月后的留存率是40%,三个月后的留存率是25%。

create external table ads_user_retention_day_rate
(
`stat_date` string comment '统计日期',
`create_date` string comment '设备新增日期',
`retention_day` int comment '截止当前日期留存天数',
`retention_count` bigint comment '留存数量',
`new_mid_count` bigint comment '设备新增数量',
`retention_ratio` decimal(10,2) comment '留存率'
) COMMENT '每日用户留存情况'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_user_retention_day_rate/';

insert into table ads_user_retention_day_rate
select
	'2020-03-10',--统计日期
	date_add('2020-03-10',-1),--新增日期
	1,  --留存天数
	sum(if(login_date_first=date_add('2020-03-10',-1) and login_date_last='2020-03-10',1,0)),   --2020-03-09 的1 日留存数
	sum(if(login_date_first=date_add('2020-03-10',-1),1,0)),                                    --2020-03-09 新增
	sum(if(login_date_first=date_add('2020-03-10',-1) and
	login_date_last='2020-03-10',1,0))/sum(if(login_date_first=date_add('2020-03-10',-1),1,0))*100
from dwt_uv_topic
union all
select
	'2020-03-10',--统计日期
	date_add('2020-03-10',-2),--新增日期
	2,--留存天数
	sum(if(login_date_first=date_add('2020-03-10',-2) and login_date_last='2020-03-10',1,0)),--2020-03-08 的2 日留存数
	sum(if(login_date_first=date_add('2020-03-10',-2),1,0)),--2020-03-08 新增
	sum(if(login_date_first=date_add('2020-03-10',-2) and
	login_date_last='2020-03-10',1,0))/sum(if(login_date_first=date_add('2020-03-10',-2),1,0))*100
from dwt_uv_topic
union all
select
	'2020-03-10',--统计日期
	date_add('2020-03-10',-3),--新增日期
	3,--留存天数
	sum(if(login_date_first=date_add('2020-03-10',-3) and login_date_last='2020-03-10',1,0)),--2020-03-07 的3 日留存数
	sum(if(login_date_first=date_add('2020-03-10',-3),1,0)),  --2020-03-07 新增
	sum(if(login_date_first=date_add('2020-03-10',-3) and
	login_date_last='2020-03-10',1,0))/sum(if(login_date_first=date_add('2020-03-10',-3),1,0))*100
from dwt_uv_topic;

7、最近连续三周活跃用户数

create external table ads_continuity_wk_count(
`dt` string COMMENT '统计日期,一般用结束周周日日期,如果每天计算一次,可用当天日期',
`wk_dt` string COMMENT '持续时间',
`continuity_count` bigint COMMENT '活跃次数'
) row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_continuity_wk_count';

insert into table ads_continuity_wk_count
select
	'2020-03-15',
	concat(date_add(next_day('2020-03-15','MO'),-7*3),'_',date_add(next_day('2020-03-15','MO'),-1)),
	count(*)
from
(
select
   mid_id
from
(
select
   mid_id
from dws_uv_detail_daycount
where dt>=date_add(next_day('2020-03-10','monday'),-7)
  and dt<=date_add(next_day('2020-03-10','monday'),-1)
group by mid_id
union all
select
   mid_id
from dws_uv_detail_daycount
where dt>=date_add(next_day('2020-03-10','monday'),-7*2)
  and dt<=date_add(next_day('2020-03-10','monday'),-7-1)
group by mid_id
union all
select
mid_id
from dws_uv_detail_daycount
where dt>=date_add(next_day('2020-03-10','monday'),-7*3)
and dt<=date_add(next_day('2020-03-10','monday'),-7*2-1)
group by mid_id
)t1
group by mid_id
having count(*)=3
)t2

8、最近七天内连续三天活跃用户数

create external table ads_continuity_uv_count(
`dt` string COMMENT '统计日期',
`wk_dt` string COMMENT '最近7 天日期',
`continuity_count` bigint
) COMMENT '连续活跃设备数'
row format delimited fields terminated by '\t'
location '/warehouse/gmall/ads/ads_continuity_uv_count';

insert into table ads_continuity_uv_count
select
'2020-03-12',
concat(date_add('2020-03-12',-6),'_','2020-03-12'),
count(*)
from
(
select mid_id
from
(
select mid_id
from
(
select
mid_id,
date_sub(dt,rank) date_dif
from
(
select
mid_id,
dt,
rank() over(partition by mid_id order by dt) rank
from dws_uv_detail_daycount
where dt>=date_add('2020-03-12',-6) and
dt<='2020-03-12'
)t1
)t2
group by mid_id,date_dif
having count(*)>=3
)t3
group by mid_id
)t4;

猜你喜欢

转载自blog.csdn.net/m0_46449152/article/details/114691339