三、Hive学习之SQL、函数
-
count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL 最慢的
-
count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL 最快的
-
count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计 仅次于count(1)
从执行效率来看
-
如果列为主键,count(列名)效率优于count(1)
-
如果列不为主键,count(1)效率优于count(列名)
-
如果表中存在主键,count(主键列名)效率最优
-
如果表中只有一列,则count(*)效率最优
-
如果表有多列,且不存在主键,则count(1)效率优于count(*)
在工作中如果没有特殊的要求,就使用count(1)来进行计数。
hive语句的执行顺序 1.from
2.join on 或 lateral view explode(需炸裂的列) tbl as 炸裂后的列名
3.where
4.group by
5.聚合函数 如Sum() avg() count(1)等
6.having 在此开始可以使用select中的别名
7.select 若包含over()开窗函数,此时select中的内容作为窗口函数的输入,窗口中所选的数据范围也是在group by,having之后,并不是针对where后的数据进行开窗,这点要注意。需要注意开窗函数的执行顺序及时间点。
8.distinct
9.order by
4、hive中大小写不敏感(列名无所谓大小写)
explain select t1.EMPNO
,t1.ENAME
,t1.JOB
from emp t1
where t1.ENAME != "SCOTT" and t1.job in(
select job
from emp
where ENAME = "SCOTT");
# 查看更加详细的执行计划,加上extended
explain extended select t1.EMPNO
,t1.ENAME
,t1.JOB
from emp t1
where t1.ENAME != "SCOTT" and t1.job in(
select job
from emp
where ENAME = "SCOTT");
// 等值比较 = == < = >
// 不等值比较 != <>
// 区间比较: select * from default.students where id between 1500100001 and 1500100010;
// 空值/非空值判断:isnull、isnotnull、nvl()、isnull()
// like、rlike、regexp用法
取整函数(四舍五入):round
向上取整:ceil
向下取整:floor
select if(1>0,1,0);
select if(1>0,if(-1>0,-1,1),0);
select score,if(score>120,'优秀',if(score>100,'良好',if(score>90,'及格','不及格'))) as pingfen from score limit 20;
select COALESCE(null,'1','2'); // 1 从左往右 依次匹配 直到非空为止
select COALESCE('1',null,'2'); // 1
select score ,case when score>120 then '优秀' when score>100 then '良好' when score>90 then '及格' else '不及格' end as pingfen from scores limit 20; select name ,case name when "施笑槐" then "槐ge" when "吕金鹏" then "鹏ge" when "单乐蕊" then "蕊jie" else "算了不叫了" end as nickname from students limit 10;
select from_unixtime(1610611142,'YYYY/MM/dd HH:mm:ss');
select from_unixtime(unix_timestamp(),'YYYY/MM/dd HH:mm:ss');
// '2021年01月14日' -> '2021-01-14'
select from_unixtime(unix_timestamp('2022年06月06日','yyyy年MM月dd日'),'yyyy-MM-dd');
// "04牛2021数加16强" -> "2021/04/16"
select from_unixtime(unix_timestamp("06牛2022数加06强","MM牛yyyy数加dd强"),"yyyy/MM/dd");
concat('123','456'); // 123456
concat('123','456',null); // NULL
select concat_ws('#','a','b','c'); // a#b#c
select concat_ws('#','a','b','c',NULL); // a#b#c 可以指定分隔符,并且会自动忽略NULL
select concat_ws("|",cast(id as string),name,cast(age as string),gender,clazz) from students limit 10;
select substring("abcdefg",1); // abcdefg HQL中涉及到位置的时候 是从1开始计数
// '2021/01/14' -> '2021-01-14'
select concat_ws("-",substring('2021/01/14',1,4),substring('2021/01/14',6,2),substring('2021/01/14',9,2));
// 建议使用日期函数去做日期
select from_unixtime(unix_timestamp('2021/01/14','yyyy/MM/dd'),'yyyy-MM-dd');
select split("abcde,fgh",","); // ["abcde","fgh"]
select split("a,b,c,d,e,f",",")[2]; // c 数组的下标依旧是从0开始
select explode(split("abcde,fgh",",")); // abcde
// fgh
select get_json_object('{"name":"zhangsan","age":18,"score":[{"course_name":"math","score":100},{"course_name":"english","score":60}]}',"$.score[1].score"); // 60
普通的聚合函数每组(Group by)只返回一个值,而开窗函数则可为窗口中的每行都返回一个值。
简单理解,就是对查询的结果多出一列,这一列可以是聚合值,也可以是排序值。
开窗函数一般就是说的是over()函数,其窗口是由一个 OVER 子句 定义的多行记录
开窗函数一般分为两类,聚合开窗函数和排序开窗函数。
注意点:
-
over()函数中的分区、排序、指定窗口范围可组合使用也可以不指定,根据不同的业务需求结合使用
-
over()函数中如果不指定分区,窗口大小是针对查询产生的所有数据,如果指定了分区,窗口大小是针对每个分区的数据
测试数据
-- 创建表
create table t_fraction(
name string,
subject string,
score int)
row format delimited fields terminated by ","
lines terminated by '\n';
-- 测试数据 fraction.txt
孙悟空,语文,10
孙悟空,数学,73
孙悟空,英语,15
猪八戒,语文,10
猪八戒,数学,73
猪八戒,英语,11
沙悟净,语文,22
沙悟净,数学,70
沙悟净,英语,31
唐玄奘,语文,21
唐玄奘,数学,81
唐玄奘,英语,23
-- 上传数据
load data local inpath '/usr/local/soft/bigdata/data/fraction.txt' into table t_fraction;
min(最小)
max(最大)
avg(平均值)
count(计数)
select name,subject,score,sum(score) over() as sumover from t_fraction;
+-------+----------+--------+----------+
| name | subject | score | sumover |
+-------+----------+--------+----------+
| 唐玄奘 | 英语 | 23 | 321 |
| 唐玄奘 | 数学 | 81 | 321 |
| 唐玄奘 | 语文 | 21 | 321 |
| 沙悟净 | 英语 | 31 | 321 |
| 沙悟净 | 数学 | 12 | 321 |
| 沙悟净 | 语文 | 22 | 321 |
| 猪八戒 | 英语 | 11 | 321 |
| 猪八戒 | 数学 | 73 | 321 |
| 猪八戒 | 语文 | 10 | 321 |
| 孙悟空 | 英语 | 15 | 321 |
| 孙悟空 | 数学 | 12 | 321 |
| 孙悟空 | 语文 | 10 | 321 |
+-------+----------+--------+----------+
select name,subject,score,
sum(score) over() as sum1,
sum(score) over(partition by subject) as sum2,
sum(score) over(partition by subject order by score) as sum3,
-- 由起点到当前行的窗口聚合,和sum3一样
sum(score) over(partition by subject order by score rows between unbounded preceding and current row) as sum4,
-- 当前行和前面一行的窗口聚合
sum(score) over(partition by subject order by score rows between 1 preceding and current row) as sum5,
-- 当前行的前面一行到后面一行的窗口聚合 前一行+当前行+后一行
sum(score) over(partition by subject order by score rows between 1 preceding and 1 following) as sum6,
-- 当前行与后一行之和
sum(score) over(partition by subject order by score rows between current row and 1 following) as sum6,
-- 当前和后面所有的行
sum(score) over(partition by subject order by score rows between current row and unbounded following) as sum7
from t_fraction;
rows:行
unbounded preceding:起点
unbounded following:终点
n preceding:前 n 行
n following:后 n 行
current row:当前行
+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
| name | subject | score | sum1 | sum2 | sum3 | sum4 | sum5 | sum6 | sum7 |
+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
| 孙悟空 | 数学 | 12 | 359 | 185 | 12 | 12 | 12 | 31 | 185 |
| 沙悟净 | 数学 | 19 | 359 | 185 | 31 | 31 | 31 | 104 | 173 |
| 猪八戒 | 数学 | 73 | 359 | 185 | 104 | 104 | 92 | 173 | 154 |
| 唐玄奘 | 数学 | 81 | 359 | 185 | 185 | 185 | 154 | 154 | 81 |
| 猪八戒 | 英语 | 11 | 359 | 80 | 11 | 11 | 11 | 26 | 80 |
| 孙悟空 | 英语 | 15 | 359 | 80 | 26 | 26 | 26 | 49 | 69 |
| 唐玄奘 | 英语 | 23 | 359 | 80 | 49 | 49 | 38 | 69 | 54 |
| 沙悟净 | 英语 | 31 | 359 | 80 | 80 | 80 | 54 | 54 | 31 |
| 孙悟空 | 语文 | 10 | 359 | 94 | 10 | 10 | 10 | 31 | 94 |
| 唐玄奘 | 语文 | 21 | 359 | 94 | 31 | 31 | 31 | 53 | 84 |
| 沙悟净 | 语文 | 22 | 359 | 94 | 53 | 53 | 43 | 84 | 63 |
| 猪八戒 | 语文 | 41 | 359 | 94 | 94 | 94 | 63 | 63 | 41 |
+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
CURRENT ROW:当前行
n PRECEDING:往前n行数据
n FOLLOWING:往后n行数据
UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING表示到后面的终点
LAG(col,n,default_val):往前第n行数据,col是列名,n是往上的行数,当第n行为null的时候取default_val
LEAD(col,n, default_val):往后第n行数据,col是列名,n是往下的行数,当第n行为null的时候取default_val
NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。
cume_dist(),计算某个窗口或分区中某个值的累积分布。假定升序排序,则使用以下公式确定累积分布:
1.1.2 排序开窗函数(重点)
-
RANK() 排序相同时会重复,总数不会变
-
DENSE_RANK() 排序相同时会重复,总数会减少
-
ROW_NUMBER() 会根据顺序计算
-
PERCENT_RANK()计算给定行的百分比排名。可以用来计算超过了百分之多少的人(当前行的rank值-1)/(分组内的总行数-1)
select name,subject,
score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rnp,
percent_rank() over(partition by subject order by score) as percent_rank
from t_fraction;
select name,subject,score,
rank() over(order by score) as row_number,
percent_rank() over(partition by subject order by score) as percent_rank
from t_fraction;
create table testArray2(
name string,
weight array<string>
)row format delimited
fields terminated by '\t'
COLLECTION ITEMS terminated by ',';
小虎 "150","170","180"
火火 "150","180","190"
select name,col1 from testarray2 lateral view explode(weight) t1 as col1;
小虎 150
小虎 170
小虎 180
火火 150
火火 180
火火 190
select key from (select explode(map('key1',1,'key2',2,'key3',3)) as (key,value)) t;
key1
key2
key3
select name,col1,col2 from testarray2 lateral view explode(map('key1',1,'key2',2,'key3',3)) t1 as col1,col2;
小虎 key1 1
小虎 key2 2
小虎 key3 3
火火 key1 1
火火 key2 2
火火 key3 3
select name,pos,col1 from testarray2 lateral view posexplode(weight) t1 as pos,col1;
小虎 0 150
小虎 1 170
小虎 2 180
火火 0 150
火火 1 180
火火 2 190
// testLieToLine
name col1
小虎 150
小虎 170
小虎 180
火火 150
火火 180
火火 190
create table testLieToLine(
name string,
col1 int
)row format delimited
fields terminated by '\t';
select name,collect_list(col1) from testLieToLine group by name;
// 结果
小虎 ["150","180","190"]
火火 ["150","170","180"]
select t1.name
,collect_list(t1.col1)
from (
select name
,col1
from testarray2
lateral view explode(weight) t1 as col1
) t1 group by t1.name;
-
继承
org.apache.hadoop.hive.ql.exec.UDF
-
重写
evaluate
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
打包的时候可能会出现错误
解决方案:
在pom文件中修改hive-exec的配置
> 打包的时候可能会出现错误 > > ### Could not transfer artifact org.pentaho:pentaho-aggdesigner-algorithm:pom:5.1.5-jhyde > 解决方案: > `在pom文件中修改hive-exec的配置`
-
-
在hive shell中,使用
add jar 路径
add jar /usr/local/soft/bigdata19/hive-bigdata19-1.0-SNAPSHOT.jar;
create temporary function fxxx1 as 'MyUDF';
select fxx1(name) as fxx_name from students limit 10;
#施笑槐$
#吕金鹏$
#单乐蕊$
#葛德曜$
#宣谷芹$
#边昂雄$
#尚孤风$
#符半双$
#沈德昌$
#羿彦昌$
# 1、将项目打包上传服务器:将打好的jar包传到linux系统中。(不要打依赖)
# 进入到hive客户端,执行下面命令
hive> add jar /usr/local/soft/bigdata17/data/xiaohu/hadoop-mapreduce-1.0-SNAPSHOT.jar
# 2、创建一个临时函数名,要跟上面hive在同一个session里面:
hive> create temporary function toUP as 'com.shujia.testHiveFun.udf.FirstUDF';
3、检查函数是否创建成功
show functions;
4. 测试功能
select toUp('abcdef');
5. 删除函数
drop temporary function if exists toUp;
hadoop fs -put hadoop-mapreduce-1.0-SNAPSHOT.jar /jar/
create function myUp as 'com.shujia.testHiveFun.udf.FirstUDF' using jar 'hdfs:/jar/hadoop-mapreduce-1.0-SNAPSHOT.jar';
create function bfy_fun as 'com.shujia.udfdemo.HiveTest' using jar 'hdfs:/shujia/bigdata19/jar/hive-udf.jar';
删除永久函数,并检查:
UDTF是一对多的输入输出,实现UDTF需要完成下面步骤
M1001#xiaohu#S324231212,lkd#M1002#S2543412432,S21312312412#M1003#bfy
1001 xiaohu 324231212
1002 lkd 2543412432
1003 bfy 21312312412
继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF, 重写initlizer()、process()、close()。 执行流程如下:
UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型)。
初始化完成后,会调用process方法,真正的处理过程在process函数中,在process中,每一次forward()调用产生一行;如果产生多列可以将多个列的值放在一个数组中,然后将该数组传入到forward()函数。
最后close()方法调用,对需要清理的方法进行清理。
"key1:value1,key2:value2,key3:value3"
key1 value1
key2 value2
key3 value3
create temporary function my_udtf as 'com.shujia.testHiveFun.udtf.HiveUDTF';
select my_udtf("key1:value1,key2:value2,key3:value3");
字段:id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12 共13列
数据:
a,1,2,3,4,5,6,7,8,9,10,11,12
b,11,12,13,14,15,16,17,18,19,20,21,22
c,21,22,23,24,25,26,27,28,29,30,31,32
转成3列:id,hours,value
例如:
a,1,2,3,4,5,6,7,8,9,10,11,12
a,0时,1
a,2时,2
a,4时,3
a,6时,4
......
create table udtfData(
id string
,col1 string
,col2 string
,col3 string
,col4 string
,col5 string
,col6 string
,col7 string
,col8 string
,col9 string
,col10 string
,col11 string
,col12 string
)row format delimited fields terminated by ',';
添加jar资源:
add jar /usr/local/soft/HiveUDF2-1.0.jar;
create temporary function my_udtf as 'MyUDTF';
select id,hours,value from udtfData lateral view my_udtf(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12) t as hours,value ;
Hive Shell
第一种:
hive -e "select * from test1.students limit 10"
hive -f hql文件路径
id datestr amount 1,2019-02-08,6214.23 1,2019-02-08,6247.32 1,2019-02-09,85.63 1,2019-02-09,967.36 1,2019-02-10,85.69 1,2019-02-12,769.85 1,2019-02-13,943.86 1,2019-02-14,538.42 1,2019-02-15,369.76 1,2019-02-16,369.76 1,2019-02-18,795.15 1,2019-02-19,715.65 1,2019-02-21,537.71 2,2019-02-08,6214.23 2,2019-02-08,6247.32 2,2019-02-09,85.63 2,2019-02-09,967.36 2,2019-02-10,85.69 2,2019-02-12,769.85 2,2019-02-13,943.86 2,2019-02-14,943.18 2,2019-02-15,369.76 2,2019-02-18,795.15 2,2019-02-19,715.65 2,2019-02-21,537.71 3,2019-02-08,6214.23 3,2019-02-08,6247.32 3,2019-02-09,85.63 3,2019-02-09,967.36 3,2019-02-10,85.69 3,2019-02-12,769.85 3,2019-02-13,943.86 3,2019-02-14,276.81 3,2019-02-15,369.76 3,2019-02-16,369.76 3,2019-02-18,795.15 3,2019-02-19,715.65 3,2019-02-21,537.71
create table deal_tb( id string ,datestr string ,amount string)row format delimited fields terminated by ',';
计算逻辑
-
先按用户和日期分组求和,使每个用户每天只有一条数据
-
根据用户ID分组按日期排序,将日期和分组序号相减得到连续登陆的开始日期,如果开始日期相同说明连续登陆
-
datediff(string end_date,string start_date); 等于0说明连续登录
-
统计用户连续交易的总额、连续登陆天数、连续登陆开始和结束时间、间隔天数
1 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL 1 2019-02-08 2991.650 5 2019-02-12 2019-02-16 1 1 2019-02-09 1510.8 2 2019-02-18 2019-02-19 1 1 2019-02-10 537.71 1 2019-02-21 2019-02-21 1 2 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL 2 2019-02-08 3026.649 4 2019-02-12 2019-02-15 1 2 2019-02-10 1510.8 2 2019-02-18 2019-02-19 2 2 2019-02-11 537.71 1 2019-02-21 2019-02-21 1 3 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL 3 2019-02-08 2730.04 5 2019-02-12 2019-02-16 1 3 2019-02-09 1510.8 2 2019-02-18 2019-02-19 1 3 2019-02-10 537.71 1 2019-02-21 2019-02-21 1
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律