介绍一些常见的数据分析场景中hive sql的一些写法,涉及区间分析,数据按条件转换,数据列转行,计算连续天数,分组排序取top N等场景。sql
多行合并经常使用于作区间统计,经过定义必定的金额区级,将上亿的记录降维为不一样区间内总数。归纳来讲就是多映射到一。 典型场景: 基于用户交易天流水,计算天天不一样金额段的金额笔数。数组
如用户的天交易流水表结构如上,须要计算出交易额在0-100,100-200,200-300,大于300几个区级的笔数,函数
CREATE VIEW t_deal_tmp_view_1 AS
SELECT
CASE
WHEN rcv_amount <= 100 THEN 1
WHEN rcv_amount <= 200 THEN 2
WHEN rcv_amount <= 300 THEN 3
ELSE 4 END AS amount_range,
receiver
FROM t_transfer_info
SELECT
amount_range,
COUNT(receiver) AS cnt
FROM t_deal_tmp_view_1
GROUP BY amount_range
DROP VIEW t_deal_tmp_view_1
复制代码
为何不使用下面这种写法ui
SELECT
CASE
WHEN rcv_amount <= 100 THEN 1
WHEN rcv_amount <= 200 THEN 2
WHEN rcv_amount <= 300 THEN 3
ELSE 4 END AS amount_range,
COUNT(receiver)
FROM t_transfer_info
GROUP BY
CASE
WHEN rcv_amount <= 100 THEN 1
WHEN rcv_amount <= 200 THEN 2
WHEN rcv_amount <= 300 THEN 3
ELSE NULL END
复制代码
这种写法会报Expressio Not In Group By Key 的错误,在hive中, 使用Group By时,非Group By的字段必须使用聚合函数,只有Group By的字段才能原值取出。
主要缘由是上面在Group By后面使用Case When没方法命名新字段。 所以须要使用临时view进行处理。spa
在hive的表中,有些记录多是NULL,这时若是咱们直接对这条记录作运算或逻辑判断是得不到咱们指望的结果的,这里能够将NULL转换为0再作处理。 固然NULL转0能够使用hive现成的函数nvl,这里使用CASE WHEN是想介绍在hive sql里条件语句的用法。3d
如上表记录用户天天的收入以及支出,天天的收入和支出可能为空,须要计算用户连续两天的总收入以及总支出。 使用join将两天的表连接进行计算,对于NULL使用替换为0,sql以下:code
SELECT
t1.uin,
t1.income + CASE WHEN t2.income IS NULL THEN 0 ELSE t2.income END AS income,
t1.expend + CASE WHEN t2.expend IS NULL THEN 0 ELSE t2.expend END AS expend
FROM
(
SELECT
uin,
income,
expend
FROM t_user_trans_inf_day
WHERE statis_day=20180812
)t1
LEFT JOIN
(
SELECT
uin,
income,
expend
FROM t_user_trans_inf_day
WHERE statis_day=20180811
)t2
ON(t1.uin=t2.uin)
复制代码
若有一个表A,如上,记录了用户的消费记录,每类消费一列,如今须要将该表的列转化为行,如表B,原来的多列转化为多行。 以下cdn
这里有两种方式能够实现,分布是使用union以及posexplode。blog
union实现方式就是分布取出单列,而后进行对结果进行合并,sql以下。 排序
SELECT uin, 1 AS type, of_amt
FROM t_user_trans
UNION ALL
SELECT uin, 2 AS type, lf_amt
FROM t_user_trans
UNION ALL
SELECT uin, 3 AS type, on_amt
FROM t_user_trans
UNION ALL
SELECT uin, 4 AS type, cr_amt
FROM t_user_trans
复制代码
explode是内建函数, 支持两种用法分别是:
explode(ARRAY) 列表中的每一个元素生成一行。
explode(MAP) map中每一个key-value对,生成一行,key为一列,value为一列。
使用explode(ARRAY)没有type列,所以没法将转换后的行对应到以前的列,这里能够使用posexplode来代替,posexplode(ARRAY)转换后,能够得到列名在数组中的位置,这样将位置对应一列进行输出便可。
SELECT
uin
t.pos+1 AS type,
t.value AS amount
FROM t_user_tans
LATERAL VIEW
posexplode(
ARRAY(
of_amt,
lf_amt,
on_amt,
cr_amt
)) t as pos, value
复制代码
有一张用户登录流水表,须要计算用户的连续登录天数,这里能够使用分组编号,Group By uin+时间减分组编号,这样连续的天数就被聚合在一块儿了,能够经过聚合函数计算最终结果。
SELECT
uin,
COUNT(uin) AS continuity_days
FROM(
SELECT
uin,
statis_day,
row_number() OVER(PARTITION BY uin order by statis_day asc) AS rn
FROM
(
SELECT
uin,
statis_day
FROM t_user_login_log
WHERE statis_day>= 20170101
AND statis_day <= 20180809
)
)
GROUP BY uin, date_sub(statis_day,CAST(rn AS INT))
复制代码
如有t_user_score记录了学生全部的科目成绩,须要取出每一个学生分数最高的一门学科。这里主要用到row_number()函数。
SELECT
uin
FROM
(
SELECT
uin,
course,
row_number() OVER(PARTITION BY uin order by score asc) AS rn
FROM
t_user_score
)
WHERE rn = 1
复制代码