09- 15 hivesql 基础

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的耗时主要在: 启动很慢,代码优劣,数据量的大小;

猜你喜欢

转载自blog.csdn.net/weixin_46400833/article/details/108591872