函数
Hive的函数分为两大类∶内置函数(Built-in Functions )、用户定义函数UDF (User-Defined Functions ) .
内置函数可分为︰数值类型函数、日期类型函数、字符串类型函数、集合函数、条件函数等;
用户定义函数根据输入输出的行数可分为3类:UDF、UDAF、UDTF。
- UDF:普通函数,一进一出
- UDAF:聚合函数,多进一出
- UDTF:表生成函数,一进多出
UDF分类标准本来针对的是用户自己编写开发实现的函数。UDF分类标准可以扩大到Hive的所有函数中︰包括内置函数和用户自定义函数。
查看所有函数
show functions ;
查看指定函数信息
-- 查看count函数信息
desc function count;
desc function extended count;
函数API文档
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF#LanguageManualUDF-Built-inFunctions
1 字符串函数
---------String Functions字符串函数-— —---------
select concat("liu", "yan")
-- 带分隔符字符串连接函数:concat_ws(separator,[string|array(string)]+)
select concat_ws('.', 'www', array('51doit', 'com'));
--字符串截取函数: substr(str, pos[, len])或者substring(str, pos[,len])
select substr("angelababy", -2); --pos是从1开始的索引,如果为负数则倒着数
select substr("angelababy", 2, 2);
-- 正则表达式替换函数: regexp_replace(str, regexp,rep)
select regexp_replace('100-200', '(\\d+)', 'num');
-- 正则表达式解析函数:regexp_extract(str,regexp[, idx]) 提取正则匹配到的指定组内容
select regexp_extract('100-200', '(\\d+)-(\\d+)', 2);
-- URL解析函数: parse_url
select parse_url('http://www.51doit.com/path/p1.php?query=1', 'HOST');
select parse_url('http://www.51doit.com/path/p1.php?query=1', 'PATH');
select parse_url('http://www.51doit.com/path/p1.php?query=1', 'QUERY');
--分割字符串函数: split(str, regex)
select split('apache hive', '\\s+');
--json解析函数: get_json_object(json_txt, path)
-- $ 获取对象
select get_json_object(
'[{"name":"柳岩","sex":"女","age":"38"},{"name":"唐嫣","sex":"女","age":"18"}]', '$.[0]');
select get_json_object(
'[{"name":"柳岩","sex":"女","age":"38"},{"name":"唐嫣","sex":"女","age":"18"}]', '$[0].name');
------------------------------------------以下自行练习------------------------------------------
-- 字符串长度函数: length(str / binary)
select length("I Love Hive");
-- 字符串反转函数: reverse
select reverse("I Love Hive");
-- 字符串连接函数:concat(stri, str2, ... strN)
-- 字符串转大写函数: upper , ucase
select upper("I Love Hive");
select ucase("I Love Hive");
-- 字符串转小写函数:lower , Lcase
select lower("I Love Hive");
select lcase("I Love Hive");
-- 去空格函数: trim去除左右两边的空格
select trim(" I Love Hive ");
-- 左边去空格函数: ltrim
select ltrim(" I Love Hive ");
-- 右边去空格函数:rtrim
select ltrim(" I Love Hive ");
-- 空格字符串函数: space(n)返回指定个数空格
select space(4);
-- 重复字符串函数:repeat(str, n)重复str字符串n
select repeat("I Love Hive", 2);
-- 首字符ascii函数: ascii
select ascii("angela");
--a对应ASCII 97
--左补足函数:lpad
select lpad('hi', 5, '*');
--右补足函数: rpad
select rpad('hi', 5, '*');
--集合查找函数:find_in_set(str ,str_array) 返回str的位置 从1开始
select find_in_set('b', 'abc,b,ab,c,def');
2 日期函数
-- 当前日期
select current_date();
-- 获取当前时问歌:current_timestamp
-- 同一查询中对current_timestamp 的所有调用均返回相同的值。
select current_timestamp();
-- 获取当前UNIX时间戳函数:unix_timestamp
select unix_timestamp();
-- 日期转UNIX时问戳函数: unix_timestamp
select unix_timestamp("2022-08-13 19:08:03");
-- 指定格式日期转UNIX时间戳函数: unix_timestamp
select unix_timestamp('20220813 19:08:03', 'yyyyMMdd HH:mm:ss');
--UNIX时间戳转日期函数:from_unixtime
select from_unixtime(1660417683);
select from_unixtime(0, 'yyyy-MM-dd HH:mm:ss');
--日期比较函数; datediff日期格式要求'yyyy-MN-dd HH:mm:ss ' or 'yyyy-MM-dd '
select datediff('2022-08-08', '2022-08-10');
-- 日期增加函数: date_add
select date_add('2022-08-08', 10);
--日期减少函数: date_sub
select date_sub('2012-08-08', 10);
-- 日期格式化
select date_format('2022-08-13 19:08:03','yyyy/MM/dd');
------------------------------------------以下自行练习------------------------------------------
-- 抽取日期函数:to_date
select to_date('2022-08-13 19:08:03');
-- 获取年:year
select year('2022-08-13 19:08:03');
-- 获取月:month
select month('2022-08-13 19:08:03');
-- 获取日:day
select day('2022-08-13 19:08:03');
-- 获取时:hour
select hour('2022-08-13 19:08:03');
-- 获取分:minute
select minute('2022-08-13 19:08:03');
-- 获取秒:second
select second('2022-08-13 19:08:03');
-- 获取周:weekofyear 指定年份的第多少周
select weekofyear('2022-08-13 19:08:03');
3 数学函数
-- 四舍五入: round返回double类型的整数值部分(四舍五入)
select round(3.1415926);
select round(3.1415926, 2);
-- 向下取整函数:floor
select floor(3.1415926);
select floor(-3.1415926);
-- 向上取整函数: ceil
select ceil(3.1415926);
select ceil(-3.1415926);
--取随机数函数: rand每次执行都不一样返回一个0到1范围内的随机数
select rand();
-- 在同一个查询中保证同一个随机数
select rand(10);
-- 二进制
select bin(100);
-- 转换进制 conv(num,现在进制,要转换的进制)
select conv(11, 10, 2);
-- 绝对值
select abs(-100);
4 集合函数
-- 创建map集合 map(k1,v1,k2,v2...)
select map('zhangsan', '18', 'lisi', '28');
-- 获取map所有的键
select map_keys(map('zhangsan', '18', 'lisi', '28'));
-- 获取map所有的值
select map_values(map('zhangsan', '18', 'lisi', '28'));
-- 获取map指定键的值
select map('zhangsan', '18', 'lisi', '28')['zhangsan'];
-- 获取map的长度
select size(map('zhangsan', '18', 'lisi', '28'));
-- 创建数组 array(值1,值2,值3);
select array(1, 3, 5, 6);
-- 数组取值
select array(3, 3, 5, 6)[0];
-- 数组长度
select size(array(3, 3, 5, 6));
-- 数组排序
select sort_array(`array`(13, 7, 5, 2, 1));
-- 创建结构体
select struct('liuyan', 38);
-- 取值
select struct('liuyan', 38).col2;
5 条件判断函数
-- if判断 类似java三元表达式 if(boolean testCondion,T valueTrue,T valueFalse)
select if(1 == 1, 'a', 'b');
-- 判断是否为空: isnull 空返回true 非空返回false
select isnull(null);
select isnull(10);
-- 判断是否非空:isnotnull 不是null返回true 是null返回false
select isnotnull(null);
select isnotnull(10);
-- nvl(T value, T defaultValue) 判断value是否为空 非空返回value, 是空返回defaultValue
select nvl("aa", "bb");
select nvl(null, "bb");
--coalesce(v1,v2,v3,v4...)返回第一个非空的值 如果都为null返回null
select coalesce(null, null, null, null);
select coalesce(null, null, 1, 2, 3, 4, null, 5, 6);
select coalesce(null, 3, 1, 2, 3, 4, null, 5, 6);
-- assert_true(条件) 条件为true 返回null 条件为false 报错
select assert_true(1 == 2);
6 脱敏加密函数
-- mask 将大写字母转换为X 小写字母转换为x 数字转换为n
select mask("abc123XYZ");
-- 将大写字母转换为- 小写字母转换为* 数字转换$
select mask("abc123XYZ",'-','*','$'); -- 自定义替换的字母
--对前n个进行脱敏 mask_first_n(String str, int n);
select mask_first_n("abc123XYZ",2);
--对后n个进行脱敏 mask_last_n(String str, int n);
select mask_last_n("abc123XYZ",4);
-- 除了前n个 其余脱敏处理
select mask_show_first_n("abc123XYZ",2);
-- 除了后n个 其余脱敏处理
select mask_show_last_n("abc123XYZ",4);
-- 返回基于str的哈希 非字符串 返回Null;
select mask_hash("abc");
-- 获取哈希值
select hash("abc");
--SHA-1加密
select sha1("abc");
--SHA-2家族算法加密 sha2(string/binary,int)(SHA-224,SHA-256,SHA-384,SHA-512)
select sha2("abc",256);
select sha2("abc",512);
--crc32加密
select crc32("abc");
--md5加密
select md5("abc");
7 调用Java函数
-- hive调用java方法
select java_method("java.lang.Math","max",100,200);
-- 反射调用
select reflect("java.lang.Math","min",100,200);
函数高级
1 行转列
这里的行转列,指的是多行转一列.输入多行输出一行
涉及的函数
concat函数 字符串拼接,不可指定分隔符
语法
concat(element1,element2,element3...)
举例
select concat('I','Love','Hive');
特点 如果任意一个元素为null,结果为null
select concat('I','Love','Hive',null);
concat_ws函数 字符串拼接,可以指定分隔符
语法
concat_ws(splitChar,e1,e2,e3....|array<String>);
举例
select concat_ws('-','I','Love','Hive');
select concat_ws('-',`array`('aa','bb','cc','dd'));
特点 任意一个元素不为null,结果就不为null
select concat_ws('-','I','Love','Hive',null);
collect_list函数 用于将一列中的多行合并为一行 不进行去重
语法
collect_list(colName)
举例
select collect_list(price) from t_product;
collect_set函数 用于将一列中的多行合并为一行 去重
语法
collect_set(colName)
举例
select collect_list(price) from t_product;
还有聚合函数 count,sum,max,avg等等
准备数据
vi emp.tsv
name gender job
柳岩 女 班主任
唐嫣 女 讲师
金莲 女 班主任
大郎 男 讲师
小庆 男 讲师
武松 男 班主任
-- 获取如下结果
女,班主任 柳岩|金莲
女,讲师 唐嫣
男,班主任 武松
男,讲师 大郎|小庆
create table t_emp
(
name string,
gender string,
job string
) row format delimited fields terminated by "\t";
load data local inpath '/root/emp.tsv' into table t_emp;
查询
-- 将gender和job合并为一列
select concat_ws(',', gender, job) as gender_job, name
from t_emp;
-- 得出结果
with t1 as (select concat_ws(',', gender, job) as gender_job, name
from t_emp)
select t1.gender_job, concat_ws('|', collect_list(name))
from t1
group by t1.gender_job;
求每种工作每种性别各有多少人,分别有谁,获取如下结果
select job,
count(*) as total,
sum(case gender when '男' then 1 else 0 end) as man,
sum(case gender when '女' then 1 else 0 end) as woman,
concat_ws('|', collect_list(name)) as names
from t_emp
group by job;
2 列传行
这里的列转行指的是将一行数据转换成多行,输入一行输出多行
涉及的函数
expload函数 用于将一个集合或者数组中的每个元素展开,将每个元素变为一行
语法
exploade(Map|Array)
举例
select explode(`array`(1,2,3,4,5));
select explode(split('a,b,c,d',','));
select explode(`map`('liuyan','38','tangyan','18'));
建表准备数据
name category
《八佰》 战争,动作,爱国,剧情
《当幸福来敲门》 剧情,励志,怀旧,心理,故事
《悬崖之上》 战争,爱国,抗日,谍战
create table t_movie
(
name string,
category string
) row format delimited fields terminated by "\t";
load data local inpath '/root/movie.txt' overwrite into table t_movie;
select * from t_movie;
查询
-- 先来炸裂所有分类
select explode(split(category, ',')) from t_movie;
-- 但是当我们加上name时 查询时 报错
-- UDTF's are not supported outside the SELECT clause, nor nested in expressions
select name, explode(split(category, ',')) from t_movie; -- 报错
我们发现在select条件中,如果只有explode函数表达式,程序执行是没有任何问题的.但是如果在select条件中,包含explode和其他字段,就会报错. 那么如何理解这个错误?为什么在select的时候,explode的旁边不支持其他字段的同时出现?
UDTF语法限制
- explode函数属于UDTF表生成函数,explode执行返回的结果可以理解为一张虚拟的表,其数据来源于源表;
- 在select中只查询源表数据没有问题,只查询explode生成的虚拟表数据也没问题,但是不能在只查询源表的时候,既想返回源表字段又想返回explode生成的虚拟表字段;通俗点讲,有两张表,不能只查询一张表但是又想返回分别属于两张表的字段;
如何解决?
1.从SQL层面上来说上述问题的解决方案是:对两张表进行join关联查询
2.Hive专门提供了语法lateral View侧视图,专门用于搭配explode这样的UDTF函数,以满足上述需要.
-- laterval view相当于自带关联条件 t_moive和t1进行 join连接
select name, t1.categroy from t_movie lateral view explode(split(category,',')) t1 as categroy;
-- 向表中添加一个没有分类的电影 category为null
vi moive2.txt
<战狼>
load data local inpath '/root/movie2.txt' into table t_movie;
select * from t_movie;
-- 查询时 发现战狼电影不显示
select name, t1.categroy
from t_movie lateral view explode(split(category, ',')) t1 as categroy;
-- 如果想显示 需要写 laterval view outer 使用outer 显示null值
select name, t1.categroy
from t_movie lateral view outer explode(split(category, ',')) t1 as categroy;
3 聚合增强
增强聚合的grouping_sets、cube、rollup这几个函数主要适用于OLAP多维数据分析模式中,多维分析中的维指的分析问题时看待问题的维度、角度。
下面我们来准备一下数据,通过案例更好的理解函数的功能含义.
2018-03,2018-03-10,cookie1
2018-03,2018-03-10,cookie5
2018-03,2018-03-12,cookie7
2018-04,2018-04-12,cookie3
2018-04,2018-04-13,cookie2
2018-04,2018-04-13,cookie4
2018-04,2018-04-16,cookie4
2018-03,2018-03-10,cookie2
2018-03,2018-03-10,cookie3
2018-04,2018-04-12,cookie5
2018-04,2018-04-13,cookie6
2018-04,2018-04-15,cookie3
2018-04,2018-04-15,cookie2
2018-04,2018-04-16,cookie1
--表创建并且加载数据
CREATE TABLE cookie_info
(
month STRING,
day STRING,
cookieid STRING
) ROW FORMAT DELIMITED
FIELDS TERMINATED BY ',';
load data local inpath '/root/cookie.txt' into table cookie_info;
select *
from cookie_info;
3.1 grouping_sets
grouping sets是一种将多个group by逻辑写在一个sql语句中的便利写法。等价于将不同维度的GROUP BY结果集进行UNION ALL。GROUPING__ID表示结果属于哪一个分组集合。
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS nums,
GROUPING__ID
FROM cookie_info
GROUP BY month,day
GROUPING SETS (month,day) --这里是关键
ORDER BY GROUPING__ID;
--等价于
SELECT month, NULL, COUNT(DISTINCT cookieid) AS nums, 1 AS GROUPING__ID
FROM cookie_info
GROUP BY month
UNION ALL
SELECT NULL as month, day, COUNT(DISTINCT cookieid) AS nums, 2 AS GROUPING__ID
FROM cookie_info
GROUP BY day;
--再比如
SELECT month,
day,
COUNT(DISTINCT cookieid) AS nums,
GROUPING__ID
FROM cookie_info
GROUP BY month, day
GROUPING SETS ( month, day, ( month, day)) --1 month 2 day 3 (month,day)
ORDER BY GROUPING__ID;
--等价于
SELECT month, NULL, COUNT(DISTINCT cookieid) AS nums, 0 AS GROUPING__ID
FROM cookie_info
GROUP BY month
UNION ALL
SELECT NULL, day, COUNT(DISTINCT cookieid) AS nums, 1 AS GROUPING__ID
FROM cookie_info
GROUP BY day
UNION ALL
SELECT month, day, COUNT(DISTINCT cookieid) AS nums, 2 AS GROUPING__ID
FROM cookie_info
GROUP BY month, day;
3.2 cube
cube表示根据GROUP BY的维度的所有组合进行聚合。
对于cube来说,如果有n个维度,则所有组合的总个数是:2^n
比如cube有a,b,c 3个维度,则所有组合情况是: (a,b,c),(a,b),(b,c),(a,c),(a),(b),©,()
SELECT
month,
day,
COUNT(DISTINCT cookieid) AS nums,
GROUPING__ID
FROM cookie_info
GROUP BY month,day
WITH CUBE
ORDER BY GROUPING__ID;
--等价于
SELECT NULL, NULL, COUNT(DISTINCT cookieid) AS nums, 0 AS GROUPING__ID
FROM cookie_info
UNION ALL
SELECT month, NULL, COUNT(DISTINCT cookieid) AS nums, 1 AS GROUPING__ID
FROM cookie_info
GROUP BY month
UNION ALL
SELECT NULL, day, COUNT(DISTINCT cookieid) AS nums, 2 AS GROUPING__ID
FROM cookie_info
GROUP BY day
UNION ALL
SELECT month, day, COUNT(DISTINCT cookieid) AS nums, 3 AS GROUPING__ID
FROM cookie_info
GROUP BY month, day;
3.3 rollup
rollup是cube的子集,以最左侧的维度为主,从该维度进行层级聚合。
比如ROLLUP有a,b,c3个维度,则所有组合情况是:(a,b,c),(a,b),(a),()
-- month和day
SELECT month,
day,
COUNT(DISTINCT cookieid) AS nums,
GROUPING__ID
FROM cookie_info
GROUP BY month, day
WITH ROLLUP
ORDER BY GROUPING__ID;
-- 等价于 所有,month,month day
SELECT NULL, NULL, COUNT(DISTINCT cookieid) AS nums, 0 AS GROUPING__ID
FROM cookie_info
UNION ALL
SELECT month, NULL, COUNT(DISTINCT cookieid) AS nums, 1 AS GROUPING__ID
FROM cookie_info
GROUP BY month
UNION ALL
SELECT month, day, COUNT(DISTINCT cookieid) AS nums, 3 AS GROUPING__ID
FROM cookie_info
GROUP BY month, day;
-- day 和month
SELECT month,
day,
COUNT(DISTINCT cookieid) AS nums,
GROUPING__ID
FROM cookie_info
GROUP BY day, month
WITH ROLLUP
ORDER BY GROUPING__ID;
-- 等价于 所有 ,day,day month
SELECT NULL, NULL, COUNT(DISTINCT cookieid) AS nums, 0 AS GROUPING__ID
FROM cookie_info
UNION ALL
SELECT null, day, COUNT(DISTINCT cookieid) AS nums, 1 AS GROUPING__ID
FROM cookie_info
GROUP BY day
UNION ALL
SELECT month, day, COUNT(DISTINCT cookieid) AS nums, 3 AS GROUPING__ID
FROM cookie_info
GROUP BY day, month;
4 窗口函数
窗口函数(Window functions )也叫做开窗函数、OLAP函数,其最大特点是∶输入值是从SELECT语句的结果集中的一行或多行的“窗口”中获取的。
窗口函数可以简单地解释为类似于聚合函数的计算函数,但是通过GROUP BY子句组合的常规聚合会隐藏正在聚合的各个行,最终输出一行,窗口函数聚合后还可以访问当中的各个行,并且可以将这些行中的某些属性添加到结果集中。
select * from stu_mark;
-- 常规分组查询 求分数和
select sname,sum(score) from stu_mark group by sname;
-- 窗口函数分组
select sname,subject,score,sum(score) over (partition by sname) as total_score from stu_mark;