本文目录:
一、行列转换
二、排名中取他值
三、累计求值
四、窗口大小控制
五、产生连续数值
六、数据扩充与收缩
七、合并与拆分
八、模拟循环操作
九、不使用distinct或group by去重
十、容器--反转内容
十一、多容器--成对提取数据
十二、多容器--转多行
十三、抽象分组--断点排序
十四、业务逻辑的分类与抽象--时效
十五、时间序列--进度及剩余
十六、时间序列--构造日期
十七、时间序列--构造累积日期
十八、时间序列--构造连续日期
十九、时间序列--取多个字段最新的值
二十、时间序列--补全数据
二十一、时间序列--取最新完成状态的前一个状态
二十二、非等值连接--范围匹配
二十三、非等值连接--最近匹配
二十四、N指标--累计去重
二十、时间序列--补全数据
表名:t20
表字段及内容:
date_id a b c
2014 AB 12 bc
2015 23
2016 d
2017 BC
问题一:如何使用最新数据补全表格
输出结果如下所示:
date_id a b c
2014 AB 12 bc
2015 AB 23 bc
2016 AB 23 d
2017 BC 23 d
参考答案:
select
date_id,
first_value(a) over(partition by aa order by date_id) as a,
first_value(b) over(partition by bb order by date_id) as b,
first_value(c) over(partition by cc order by date_id) as c
from
(
select
date_id,
a,
b,
c,
count(a) over(order by date_id) as aa,
count(b) over(order by date_id) as bb,
count(c) over(order by date_id) as cc
from t20
)tmp1;
二十一、时间序列--取最新完成状态的前一个状态
表名:t21
表字段及内容:
date_id a b
2014 1 A
2015 1 B
2016 1 A
2017 1 B
2013 2 A
2014 2 B
2015 2 A
2014 3 A
2015 3 A
2016 3 B
2017 3 A
上表中B为完成状态。
问题一:取最新完成状态的前一个状态
输出结果如下所示:
date_id a b
2016 1 A
2013 2 A
2015 3 A
参考答案:
此处给出两种解法,其一:
select
t21.date_id,
t21.a,
t21.b
from
(
select
max(date_id) date_id,
a
from
t21
where
b = 'B'
group by
a
) t1
inner join t21 on t1.date_id -1 = t21.date_id
and t1.a = t21.a;
其二:
select
next_date_id as date_id
,a
,next_b as b
from(
select
*,min(nk) over(partition by a,b) as minb
from(
select
*,row_number() over(partition by a order by date_id desc) nk
,lead(date_id) over(partition by a order by date_id desc) next_date_id
,lead(b) over(partition by a order by date_id desc) next_b
from(
select * from t21
) t
) t
) t
where minb = nk and b = 'B';
问题二:如何将完成状态的过程合并
输出结果如下所示:
a b_merge
1 A、B、A、B
2 A、B
3 A、A、B
参考答案:
select
a
,collect_list(b) as b
from(
select
*
,min(if(b = 'B',nk,null)) over(partition by a) as minb
from(
select
*,row_number() over(partition by a order by date_id desc) nk
from(
select * from t21
) t
) t
) t
where nk >= minb
group by a;
二十二、非等值连接--范围匹配
表f是事实表,表d是匹配表,在hive中如何将匹配表中的值关联到事实表中?
表d相当于拉链过的变化维,但日期范围可能是不全的。
表f:
date_id p_id
2017 C
2018 B
2019 A
2013 C
表d:
d_start d_end p_id p_value
2016 2018 A 1
2016 2018 B 2
2008 2009 C 4
2010 2015 C 3
问题一:范围匹配
输出结果如下所示:
date_id p_id p_value
2017 C null
2018 B 2
2019 A null
2013 C 3
**参考答案:
此处给出两种解法,其一:
select
f.date_id,
f.p_id,
A.p_value
from f
left join
(
select
date_id,
p_id,
p_value
from
(
select
f.date_id,
f.p_id,
d.p_value
from f
left join d on f.p_id = d.p_id
where f.date_id >= d.d_start and f.date_id <= d.d_end
)A
)A
ON f.date_id = A.date_id;
其二:
select
date_id,
p_id,
flag as p_value
from (
select
f.date_id,
f.p_id,
d.d_start,
d.d_end,
d.p_value,
if(f.date_id between d.d_start and d.d_end,d.p_value,null) flag,
max(d.d_end) over(partition by date_id) max_end
from f
left join d
on f.p_id = d.p_id
) tmp
where d_end = max_end;
二十三、非等值连接--最近匹配
表t23_1和表t23_2通过a和b关联时,有相等的取相等的值匹配,不相等时每一个a的值在b中找差值最小的来匹配。
t23_1和t23_2为两个班的成绩单,t23_1班的每个学生成绩在t23_2班中找出成绩最接近的成绩。
表t23_1:a中无重复值
a
1
2
4
5
8
10
表t23_2:b中无重复值
b
2
3
7
11
13
问题一:单向最近匹配
输出结果如下所示:
注意:b的值可能会被丢弃
a b
1 2
2 2
4 3
5 3
5 7
8 7
10 11
参考答案:
select
*
from
(
select
ttt1.a,
ttt1.b
from
(
select
tt1.a,
t23_2.b,
dense_rank() over(partition by tt1.a order by abs(tt1.a-t23_2.b)) as dr
from
(
select
t23_1.a
from t23_1
left join t23_2 on t23_1.a=t23_2.b
where t23_2.b is null
) tt1
cross join t23_2
) ttt1
where ttt1.dr=1
union all
select
t23_1.a,
t23_2.b
from t23_1
inner join t23_2 on t23_1.a=t23_2.b
) result_t
order by result_t.a;
二十四、N指标--累计去重
假设表A为事件流水表,客户当天有一条记录则视为当天活跃。
表A:
time_id user_id
2018-01-01 10:00:00 001
2018-01-01 11:03:00 002
2018-01-01 13:18:00 001
2018-01-02 08:34:00 004
2018-01-02 10:08:00 002
2018-01-02 10:40:00 003
2018-01-02 14:21:00 002
2018-01-02 15:39:00 004
2018-01-03 08:34:00 005
2018-01-03 10:08:00 003
2018-01-03 10:40:00 001
2018-01-03 14:21:00 005
假设客户活跃非常,一天产生的事件记录平均达千条。
问题一:累计去重
输出结果如下所示:
日期 当日活跃人数 月累计活跃人数_截至当日
date_id user_cnt_act user_cnt_act_month
2018-01-01 2 2
2018-01-02 3 4
2018-01-03 3 5
参考答案:
SELECT tt1.date_id
,tt2.user_cnt_act
,tt1.user_cnt_act_month
FROM
( -- ④ 按照t.date_id分组求出user_cnt_act_month,得到tt1
SELECT t.date_id
,COUNT(user_id) AS user_cnt_act_month
FROM
( -- ③ 表a和表b进行笛卡尔积,按照a.date_id,b.user_id分组,保证截止到当日的用户唯一,得出表t。
SELECT a.date_id
,b.user_id
FROM
( -- ① 按照日期分组,取出date_id字段当主表的维度字段 得出表a
SELECT from_unixtime(unix_timestamp(time_id),'yyyy-MM-dd') AS date_id
FROM test.temp_tanhaidi_20211213_1
GROUP BY from_unixtime(unix_timestamp(time_id),'yyyy-MM-dd')
) a
INNER JOIN
( -- ② 按照date_id、user_id分组,保证每天每个用户只有一条记录,得出表b
SELECT from_unixtime(unix_timestamp(time_id),'yyyy-MM-dd') AS date_id
,user_id
FROM test.temp_tanhaidi_20211213_1
GROUP BY from_unixtime(unix_timestamp(time_id),'yyyy-MM-dd')
,user_id
) b
ON 1 = 1
WHERE a.date_id >= b.date_id
GROUP BY a.date_id
,b.user_id
) t
GROUP BY t.date_id
) tt1
LEFT JOIN
( -- ⑥ 按照date_id分组求出user_cnt_act,得到tt2
SELECT date_id
,COUNT(user_id) AS user_cnt_act
FROM
( -- ⑤ 按照日期分组,取出date_id字段当主表的维度字段 得出表a
SELECT from_unixtime(unix_timestamp(time_id),'yyyy-MM-dd') AS date_id
,user_id
FROM test.temp_tanhaidi_20211213_1
GROUP BY from_unixtime(unix_timestamp(time_id),'yyyy-MM-dd')
,user_id
) a
GROUP BY date_id
) tt2
ON tt2.date_id = tt1.date_id
网友评论