hivesql 基础:
hive简介:
hive是基于hadoop的数据仓库
mapreduce简介:
基础语法:
查询语句:select a from b where c ;
Groupby 分组
Order by 排序
执行顺序:
From(先读取表)-> where (筛选)–> group by (聚合分组)-> having-> select(选择) order by(排序)
Group by 执行顺序在select之前(先分组再查询);
常用函数:
1、 如何把时间戳转化为日期
2、 如何计算日期间隔
截取时间函数:
dt=2019-01-01 19:55:55
to_data(dt)=2019-01-01
year(dt)= 2019 截取年
month(dt)=01 截取月
hour(dt)=19
substr( string f,int start ,int end) 字符串截取函数
substr(dt,1,10) =2019-01-01
substr(dt,6) 截取从第六位到最后一位;
3、 条件函数
前提两个表:user_info用户信息表,user_trade 用户交易表:
3-1 、case when
Eg: 统计四个年龄段20岁以下,2030岁,3040岁,40岁以上的用户数:
Select 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,
Count(distinct user_id)user_num 这一句是对user_id 去重
From user_info
Group by 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;
注意:group by 执行在select之前,所以后边的重命名不生效,只能在select后边重命名。
3-2 、if
统计每个性别用户等级高低的分别情况(level>5位高级)
分类汇总的字段有两个:性别,高低等级
Select sex , if(level>5, ’高’ , ’低’) as level_type,
Count(distinct user_id) user_num
From user_info
Group by sex,if(level>5 , ‘高’,’低’);
解析: if中条件满足则注释为高,否则注释为低;
4、 字符串函数
4-1
Substr( string a, int start ,int end)
每个月新激活的用户:
Select substr(firstactivetime,1,7) as month,
Count(distinct user_id) user_num
From user_info
Group by substr( firstactivetime ,1,7);
4-2
Substr( string a , int start ,int len) 若不指定截取长度,则截止末尾;
4-3
Get_json_object( stringjson_string, string path)
Param1: 需要解析的json字段
Param2:用key取出想要获取的value值
Extra1(string) (“sysytemtyoe”:”ios”,”education”:”master”,”marriage_status”:”1”,”phonebrand”:”iphonex”)
Extra2(map<string:string “sysytemtyoe”:”ios”,”education”:”master”,”marriage_status”:”1”,”phonebrand”:”iphonex”)
对于键值对类型数据,有些公司以string形式存储,有些公司存储map型,不同类型的数据处理需要使用不同的字符串函数;
方法1、select get_json_object(extra1 ,’ . p h o n e b r a n d ’ ) a s p h o n e b r a n d , C o u n t ( d i s t i n c t u s e r i d ) u s e r n u m F r o m u s e r i n f o G r o u p b y g e t j s o n o b j e c t ( e x t r a 1 , ’ .phonebrand’) as phone_brand, Count(distinct user_id) user_num From user_info Group by get_json_object(extra1,’ .phonebrand’)asphonebrand,Count(distinctuserid)usernumFromuserinfoGroupbygetjsonobject(extra1,’.phonebrand’);
$ 作用是表明要获取那个key对应的value值;
方法二:
Select extra2[‘phonebrand’] as phone_brand,
Count(distinct user_id) user_num
From user_info
Group by extra2[‘phonebrand’];
注意: 查得的结果都是 string
要查两个字段:必须分开写两遍,不能写一起:
Eg:
Select extra2[‘phonebrand’] as phone_brand,
Extra2[‘marriage_status’] as marriage_status,
Count(distinct user_id) user_num
From user_info
Group by extra2[‘phonebrand’];
不能:
extra2[‘phonebrand’,’marriage_atstus’] as phone_brand,
5、 聚合统计函数
就是常用的 sum average max min count等;
注意: 聚合函数不可以互相嵌套( avg(count(*))
例如:
求一elly用户的2018年的平均支付金额,以及2018年最大的支付日期与最小支付日期的间隔
应用:时间戳时 秒,需要通过from_unixtime转化为想要的格式的函数
日期差函数 datadiff
Select avg(pay_amount) as pay_aomunt,
Datadiff(max(from_unixtime(pat_time,’yyyy-mm-dd’)),min(from_unixtime(pay_time,’yyyy-mm-dd’)))
From user_trade
Where year(dt)=’2018’ and user_name=’ELLA’;
练习题:
1、2018年购买的商品种类在两个以上的用户数:
思路:
1、 先求出每个人购买的商品数
2、 商品数大于2的用户
3、统计符合条件的用户数
Select count (distinct a.user_name)
From
(select user_name ,count(distinct goods_category) as category_num from user_trade
Where year(dt)=’2018’
Group by user_name
Having count(distinct gooods_category)>2)a;
2、用户激活时间在2018年,年龄端在20-30岁和30-40岁之间的婚姻情况
思路:
1、 选出激活时间在2018年的用户,并把他们所在年龄计算好,并提出婚姻状况
2、 取出年龄在20-30和30-40的用户,把他们的婚姻情况转义为可理解的说明
3、 聚合计算,针对年龄段,婚姻情况的聚合
Select a.age_type,
if( a.marriage_status=1,’已婚’,’未婚’),
count( distinct a.user_id)
from
(Select 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’,
Get_json_object( extra, ‘$.marriage_status’) as marriage_status,
From user_info
Where to_data(dt) between ‘2018-01-01’ and ‘2018-12-31’)
a
where a.age_type in (’20-30岁’,’30-40岁’)
group by a.age_type, if( a.marriage_status=1,’已婚’,’未婚’);
方法二:
Select a.age_type,
if( a.marriage_status=1,’已婚’,’未婚’),
count( distinct a.user_id)
from
(Select if ( age>=20 and age<30, ’20-30岁’,’30-40岁’) as ‘age_type’,
Get_json_object( extra, ‘$.marriage_status’) as marriage_status,
From user_info
Where to_data(dt) between ‘2018-01-01’ and ‘2018-12-31’ and age betwee 20 and 40) a
where a.age_type in (’20-30岁’,’30-40岁’)
group by a.age_type, if( a.marriage_status=1,’已婚’,’未婚’);
数据库中所有是否的存储记录为 1,0;1为是,0为否;
常见错误:
1、 标点符号错误: 全角符号和半角符号,中文无全角半角之分,英文有全角半角区别;
2、没有对子查询的表进行重命名
子查询 :的结果会形成一个新的表;
例如:
(select user_name ,count(distinct goods_category) as category_num from user_trade
Where year(dt)=’2018’
Group by user_name
Having count(distinct gooods_category)>2)a;
3、会写错字段名
Username —应该是 user_name
Hive中不管存什么类型的数据内容,多数公司存储为string,因为string较通用;
总结:
1、 利用group by做聚合计算
2、 利用order by做计算
3、 牢记SQL执行顺序
4、 常见函数的组合使用
5、 避免常见错误
Hive进阶知识:
数据分析是高危工作,必须检查,数据准确准确再准确!!!!!!
代码目标:以大数据量为基础,写代码不伤害集群,查出结果
连接:
内连接(inner join):返回两个标的交集部分
多表连接使用一对一的字段连接(最好是使用主键字段连接)
Eg-1:
找出即在user_list1又在user_list2的用户:
Select * from user_list1 a inner join user_list2 b on a.user_id=b.user.id;
返回结果为
1001 abbh 1001 abby
1002 anj 1002 anj
注:因为select *,所有返回结果为 list1中满足条件的字段,也包括list2中满足条件的字段。
表连接时,必须进行重命名;
On后面使用的连接条件必须起到唯一性作用
Inner 可以省略不写,效果一样;
Eg-2
在2019年购买后又退款的用户
Select a.user_name ##a.user_name 可以更换为b.user_name,但是如果不加a或b子表限制,就会返回双重值,没必要。
From
(select distinct user_name
From user_trade
Where year(dt)=2019)a
Inner join 内部去重
(select distinct user_name
From user_refused
Where year(dt)=2019)b
On a.user_name=b.user_name;
Select a.user_name
Count(distinct a.user_name) —外部去重
From
(select distinct user_name
From user_trade
Where year(dt)=2019)a
Inner join
(select distinct user_name
From user_refused
Where year(dt)=2019)b
On a.user_name=b.user_name;
1、如果不去冲就会两倍结果;
2. 内部去重,先去重再连接,可以提高效率,(内部去重使子查询获得简单的小表,后续查询会更快)
在2017年,2018年,2019年都有交易的用户(三个表的交集)
第一种写法:
Select distinct a.user_name 外部去重
From trade_2017 a
Join trade_2018 b on a.user_name = b.user_name
Join trade_2019 c on b.user_name = c.user_name;
Select distinct a.user_name
From trade_2017 a join trade_2018 b join trade_2019 c
On a.user_name = b.user_name =c.user_name;
这种写法hive不支持,mysql支持;
方法二:
Select a.user_name
From
(select distinct user_name
From trade_2017)a
join
(select distinct user_name
From trade_2018)b on a.user_name =b.user_name
join
(select distinct user_name
From trade_2019) c on b.user_name = c.user_name;
当数据量大时,不管大不大,都采用内部去重,因为子表小,查询步骤进行时更快;
注意:
外链接—左连接 left join
因为有链接很容易出错
进行左连接后,以左边的表1为准,返回能够匹配上的右边表2的结果,没有匹配上则返回null;
Left join 关键字从坐标、表中返回所有的行,及时由表中没有匹配,返回null;
例如:
表1 表2
10 qwe 10 qwe
11 wer 12 ert
13 yu 13 yu
14 ui 18 ji
返回结果为:
10 qwe 10 qwe
11 wer null null
13 yu 13 yu
14 ui null null
例如:在表1中存在但不在表2中的用户:
(因为表2中不存在,所以不能 b.user_name)
Select a.user_id,a.user_name
From user_list1 a left join user_list2 b on a.user_id=b.user_id
Where b.user_name is null ;
解析:
1、 From user_list1 a left join user_list2 b on a.user_id=b.user_id
2、 返回的只是一个子表
形如:
10 qwe 10 qwe
11 wer null null
13 yu 13 yu
14 ui null null
所以需要对其中的null再次筛选
Where b.user_name is null ;
注:逻辑值 true false null 只能用is 判断,不能用=;
Eg-2
在2019年购买,但是没有退款的用户(在a表-交易表 不在b表=退款表)
Select a.user_name
From
(select distinct user_name
From trade_2019
Where year(dt)=2019)a
Left join
(select distinct user_name
From user_refused
where year(dt)=2019) b on a.user_name = b.user_name
where b.user_name is null;
MySQL中可以用 not in(子查询) 写,但是hive中不能再in后加子查询;
自己写的SQL语句,map数在10000以上就已经很危险了,需要优化,一般10000以下;
Hive的耗时主要在: 启动很慢,代码优劣,数据量的大小;