目标:
1、掌握hive基础语法、常用函数及其组合使用
2、掌握一些基本业务指标的分析思路与实现技巧
一、基础语法
1、SELECT ... A... FORM ...B... WHERE ...C...
1)某次经营活动中,商家发起了“异性拼团购”,试着针对某个地区的用户进行推广,找出匹配用户。
"选出城市在北京,性别位女的10个用户名"
select user_name
from user_info
where city='beijing' and sex='female'
limit 10;
注意:如果该表是一个分区表,则where条件中必须对分区字段进行限制
2)选出在2018年12月31日,购买的商品品类是food的用户名、购买数量、支付金额
select user_name
,piece
,pay_amount
from user_trade
where dt='2018-12-31' and goods_category='food';
2、GROUP BY(分类汇总)
3)试着对本公司2019年第一季度商品的热度与价值度进行分析。
"2019年一月到三月,每个品类有多少人购买,累计金额是多少"
SELECT goods_category
,count(user_name) as user_num
,sum(pay_amount) as total_amount
from user_trade
WHERE dt between '2019-01-01' and '2019-03-31'
group by goods_category
常用的聚会函数:
1、count():计数 count(distinct...)去重计数
2、sum():求和
3、avg():平均值
4、max():最大值
5、min():最小值
GROUP BY ... HAVING(分类汇总过滤)
4)找出在2019年4月支付金额超过5万元的用户,给这些VIP用户赠送优惠券
SELECT user_name,sum(pay_amount) as total_amount
from user_trade
WHERE dt between '2019-04-01' and '2019-04-30'
group by user_name
HAVING sum(pay_amount)>50000;
3、ORDER BY(排序)
5)2019年4月,支付金额最多的TOP5用户
SELECT user_name,sum(pay_amount) as total_amount
from user_trade
WHERE dt between '2019-04-01' and '2019-04-30'
group by user_name
order by total_amount desc
limit 5;
(由于执行顺序的原因,ORDER BY 后面要使用重新定义的列名进行排序,具体执行顺序参考MySQL)
ASC:升序(默认) DESC:降序
对多个字段进行排序:ORDER BY A ASC, B DESC,每个字段都要指定升序或者降序
二、常用函数
查看Hive中的函数:show functions;
查看具体函数的用法:1)desc function 函数名;2)desc function extended函数名;
1、如何把时间戳转化为日期(from_unixtime)?
6)
SELECT pay_time,
from_unixtime(pay_time,'yyyy-MM-dd hh:mm:ss')
from user_trade
WHERE dt='2019-04-09'
from_unixtime(bigint unixtime,string format):将时间戳转化为指定格式的日期
format:
1.yyyy-MM-dd hh:mm:ss
2.yyyy-MM-dd hh
3.yyyy-MM-dd hh:mm
4.yyyyMMdd
拓展:把日期转化为时间戳:unix——timestamp(string date)
2、如何计算日期间隔?(datediff 函数)
7)用户的首次激活时间,与2019年5月1日的日期间隔。
SELECT user_name
,datediff('2019-05-01',to_date(firstactivetime))
from user_info
limit 10;
datediff(string enddate,string startdate):结束日期减去开始日期的天数
拓展:日期增加函数(增加天数)、减少函数(减少天数) —— date_add、date_sub(类型要是string类型的)
date_add(string startdate,int days)、date_sub(string startdate,int days)
3、条件函数(case when 和 if 函数)
case when 函数
8)统计以下四个年龄段20岁以下、20-30岁、30-40岁、40岁以上的用户数
SELECT
case
when age<20 then '20岁以下'
when age<30 then '20-30岁'
when age<40 then '30-40岁'
else '40岁以上' end as age_type,
count(distinct user_id) as user_num
from user_info
group by ( case
when age<20 then '20岁以下'
when age<30 then '20-30岁'
when age<40 then '30-40岁'
else '40岁以上' end )
case when 的时候不用加group by,只有在聚合函数的时候才需要group by
if 函数
9)统计每个性别的用户等级高低分布情况(假设level大于5为高级,注意列名不能使用中文的)
SELECT sex,
if(level>5,'高级','低级') as level_type,
count(distinct user_id) as user_num
from user_info
group by sex,
if(level>5,'高级','低级');
4、字符串函数(substr 和 substring 函数)
10)分析每个月都拉新情况
select substring(firstactivetime,1,7) as month
,count(distinct user_id) as user_num
from user_info
group by substring(firstactivetime,1,7);
substring(stringA,INT start,int len),substr(stringA,INT start,int len),截取起始位置和截取长度
json文本格式解析函数
extra1需要解析json字段,然后用$.key取出想要获取的value;
extra2使用的是中括号加引号的方式进行字段提取和分组;
两种写法要看字段类型的不同采取不同的方式
11)求不同手机品牌的用户数
extra1(string):
{"systemtype":"ios","education":"master","marriage_status":"1","phonebrand":"iphoneX"}
extra2(map<string,string>):
{"systemtype":"ios","education":"master","marriage_status":"1","phonebrand":"iphone X"}
第一种情况:
select get_json_object(extra1,'$.phonebrand') as phone_brand
,count(distinct user_id) as user_num
from user_info
group by get_json_object(extra1,'$.phonebrand');
第二种情况:
select extra2["phonebrand"] as phone_brand
,count(distinct user_id) as user_num
from user_info
group by extra2["phonebrand"];
extra1需要解析json字段,然后用$.key取出想要获取的value;
extra2使用的是中括号加引号的方式进行字段提取和分组;
两种写法要看字段类型的不同采取不同的方式
5、聚合统计函数
12)ELLA用户的2018年的平均每次支付金额,以及2018年最大的支付日期和最小的支付日期的间隔
SELECT AVG(pay_amount),
max(from_unixtime(pay_time,'yyyy-MM-dd')),
min(from_unixtime(pay_time,'yyyy-MM-dd')),
datediff(max(from_unixtime(pay_time,'yyyy-MM-dd')), min(from_unixtime(pay_time,'yyyy-MM-dd')))
from user_trade
WHERE substr(dt,1,4)='2018' and user_name='ELLA'
#如果要使用user_name,则要多加group by进行分组,having后用不了本题的限制条件
SELECT user_name,
AVG(pay_amount),
max(from_unixtime(pay_time,'yyyy-MM-dd')),
min(from_unixtime(pay_time,'yyyy-MM-dd'))
from user_trade
WHERE substr(dt,1,4)='2018'
GROUP BY user_name
三、重点练习
13)2018年购买的商品品类在两个以上的用户数
步骤一:
SELECT user_name,count(distinct goods_category)
from user_trade
where substr(dt,1,4)='2018'
group by user_name
having count(distinct goods_category)>=2;
步骤二:
select count(a.user_name)
from
(SELECT user_name,count(distinct goods_category)
from user_trade
where substr(dt,1,4)='2018'
group by user_name
having count(distinct goods_category)>=2) as a
步骤总结:
1、先求出每个人购买的商品品类书
2、筛选出购买商品品类书大于2的用户
3、统计符合条件的用户有多少个
14)用户激活时间在2018年,年龄段在20-30岁和30-40岁的婚姻情况分布
错误方法(也能得出正确的结果,只是计算方式会比较慢):
select b.age_type,count(distinct b.user_id),if(b.marriage_status=1,"已婚","未婚")
from
(select user_id
,user_name
,(case
when age<20 then "20岁以下"
when age>=20 and age<30 then "20-30岁"
when age>=30 and age<40 then "30-40岁"
else '40岁以上'
end) as age_type
,extra2["marriage_status"] as marriage_status
from user_info
where year(firstactivetime)='2018'
group by user_id
,user_name
,(case
when age<20 then "20岁以下"
when age>=20 and age<30 then "20-30岁"
when age>=30 and age<40 then "30-40岁"
else '40岁以上'
end)
,extra2["marriage_status"])as b
where age_type in ("20-30岁", "30-40岁")
group by b.age_type,if(b.marriage_status=1,"已婚","未婚")
正确方式:
select b.age_type,count(distinct b.user_id),if(b.marriage_status=1,"已婚","未婚")
from
(select user_id
,user_name
,(case
when age<20 then "20岁以下"
when age>=20 and age<30 then "20-30岁"
when age>=30 and age<40 then "30-40岁"
else '40岁以上'
end) as age_type
,extra2["marriage_status"] as marriage_status
from user_info
where year(firstactivetime)='2018' )as b
where age_type in ("20-30岁", "30-40岁")
group by b.age_type,if(b.marriage_status=1,"已婚","未婚")
步骤总结:
1、先选出激活时间在2018年的用户,并把他们所在的年龄段计算好,并提取出婚姻状况;
如何select后面没有进行聚合,则可以不用使用group by,直接使用where进行过滤就可以;
2、取出年龄段在20-30岁和30-40岁的用户,把他们的婚姻状况转义成可理解的说明;
3、聚合计算,针对年龄段,婚姻状况的聚合