回顾总结
hive表的类型 :内部表和外部表
删除内部表会删除表的所有数据
删除外部表只会删除表的元数据,hdfs上的行数据会保留
表的分区和分桶
本质都是对表数据的拆分存储
分区的方式 是通过创建不同的目录来拆分数据 ,根据数据本身的内容最为目录名
分桶的方式 是通过创建不同的文件来拆分数据 文件名时hash取余的名字
数据拆分后可以提升数据的查询效率
分桶还有特殊使用场景
分桶关联多张表
分桶随机采样
序列化
本质就是对hdfs上的文件数据进行读取和写入
可以通过row format delimited fields terminated by ',' 指定如何读取和写入hdfs上的字段数据
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name( col_name data_type [COMMENT col_comment] ) [COMMENT table_comment] hive中的独有语法 -- 分区字段指定,分区字段是不能表字段重复 [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] -- 分桶字段,需要指定表中存在的字段 [CLUSTERED BY (col_name, col_name, ...) INTO num_buckets BUCKETS] -- 指定分割符 默认的字段分割符\001 [ROW FORMAT row_format] -- 指定表的存储目录位置 不指定默认是在对应的数据库目录下创建表目录 [LOCATION hdfs_path]
一、内置函数
内置函数时hive中自带的函数方法,用来对不同类型的字段数据进行操作
字符串,数值,条件判断
字符串方法
length concat concat_ws substr split regexp_replace% round() ceil() floor()if() case when 条件1 then 结果 when 条件2 then 结果 when 条件3 then 结果 else 前面条件都不成返回的结果 end 字段名称-- 查看hive中的所有内置函数 show functions; -- 查看函数的具体用户 desc function extended 函数名;
1-1 日期类型操作
-- 获取当前日期 select `current_date`(); -- 获取当前日期时间 select `current_timestamp`(); -- 获取unix时间(时间戳) 从1970年1月1号0时0分0秒 到现在过去了多少秒 select unix_timestamp(); -- unix时间 和日期时间的转化 -- 日期时间转为unix select unix_timestamp('2023-10-01 15:30:28'); -- 将unix时间转为日期时间 select from_unixtime(12390886789); -- 年月日的取值 select year('2023-10-01 15:30:28'); select month('2023-10-01 15:30:28'); select day('2023-10-01 15:30:28'); select dayofmonth('2023-10-12 15:30:28'); select dayofweek('2023-10-12 15:30:28'); select hour('2023-10-12 15:30:28'); select minute('2023-10-12 15:30:28'); select second('2023-10-12 15:30:28'); -- 时间加减 select date_add('2023-10-12 15:30:28',5); select date_add('2023-10-12 15:30:28',-5); -- 比较时间相差多少天 select datediff(`current_date`(),'2023-10-12');
1-2 类型转化
-- 字段类型不符合计算需求,可以进行类型转化 -- 隐式转化 hive会自动判断进行转化数据然后计算 select '123'+'456'; -- 手动指定转化 select cast('123' as int) + cast('456' as int); select * from itcast.tb_hero; desc itcast.tb_hero; -- 转化只是在计算时进行,并不会改变字段本身类型 select cast(blood as bigint) from itcast.tb_hero;
1-3 字符串数据转json,array,map操作
-
josn字符串操作
-
数据是一个 "{key:value}" 格式
-
使用方法取值value
-
create table tb_order_detail( json_field string ); select * from tb_order_detail; -- 对字段中的json字符串数据进行取值,按照key取value值 -- 方法一 get_json_object 每次只能取一个字段数据 ,可以向下一直取值 select get_json_object(json_field,'$.orderid') as orderid, get_json_object(json_field,'$.total_price') as total_price, get_json_object(json_field,'$.total_num') as total_num, get_json_object(json_field,'$.goods') as goods, get_json_object(json_field,'$.goods[0]') as good1, get_json_object(json_field,'$.goods[0].name') as good1_name, get_json_object(json_field,'$.goods[1]') as good2 from tb_order_detail; -- json_tuple 一次取多个字段值,不能对嵌套数据往下取值 select json_tuple(json_field,'orderid','total_price','total_num','goods') as(orderid,total_price,total_num,goods) from tb_order_detail
将字符串数据切割转为数组数据
create table tb_user( id int, name string, hobby string )row format delimited fields terminated by ','; select id,name,split(hobby,'-') from tb_user;
将字符串数据切割转为map数据
-- 使用map方法 select `map`('name','张三','age',29); create table tb_hero( id int, name string, blood int, skin string )row format delimited fields terminated by ','; -- 西部大镖客:288-大圣娶亲:888-全息碎片:0-至尊宝:888-地狱火:1688 --> {'西部大镖客':288,'大圣娶亲':88} select id,name,blood,map(split(split(skin,'-')[0],":")[0], cast(split(split(skin,'-')[0],":")[1] as int),split(split(skin,'-')[1],":")[0],cast(split(split(skin,'-')[1],":")[1] as int))from tb_hero;
mysql中的内置函数操作
select concat(name,sex) from member; select concat_ws(',',name,sex) from member; select substr(s_birth,1,4) from student; select replace(s_birth,'-','/') from student; select round(3.1421,2); select round(3.123); select pow(2,3); select current_timestamp; select current_date; select unix_timestamp(); select unix_timestamp('2023-10-10 10:10:10'); select from_unixtime(127381923); select date_add('2023-10-10 10:10:10',interval 1 day); select date_add('2023-10-10 10:10:10',interval 1 month ); select date_add('2023-10-10 10:10:10',interval 1 year ); select date_add('2023-10-10 10:10:10',interval -1 year ); select date_add('2023-10-10 10:10:10',interval -1 hour ); select timestampdiff(year ,'2020-02-02','2023-02-02'); select timestampdiff(month ,'2020-02-02','2023-02-02'); select timestampdiff(day ,'2020-02-02','2023-02-02'); select timestampdiff(hour ,'2020-02-02 16:23:12','2023-02-02 15:12:12'); select if(s_sex='男',1,2),s_sex from student; select *, case when year(s_birth) between 1980 and 1989 then '80后' when year(s_birth) between 1990 and 1999 then '90后' end from student;
二、DQL的查询计算(掌握)
对表进行查询计算
select 字段 from 表; select 字段1,字段2,字段3,常量值,内置函数计算 from tb
2-1 单表查询计算
where 的条件过滤
select 字段1,字段2,字段3,常量值,内置函数计算 from tb where 过滤条件
过滤条件,条件成立的将对的行数据返回
-
比较大小
-
字段 = 数值 判断字段和数值是否相等
-
字段 > 数值
-
字段 < 数值
-
字段 >= 数值
-
字段 <= 数值
-
字段 != 数值
-
-- 大小比较 -- 年龄大于19岁 select * from tb_stu where age >19; -- 查询性别为女性的学生信息 select * from tb_stu where gender='女'; -- 查询学科不是IS的学生信息 select * from tb_stu where cls !='IS';
-
判断空值
-
字段 is null 字段为空
-
字段 is not null
-
-- 空值判断 insert into tb_stu values(9023,null,'男',20,'MA'); select * from tb_stu where name is not null; select * from tb_stu where name is null; select * from tb_stu where name !=''; -- 空字符过滤是会将null值一起过滤掉 select * from tb_stu where name =''; -- 相等判断是,空字符是不会过滤出null值的
-
范围判断
-
字段 between 数值1 and 数值2
-
字段 >=数值 and 字段 <=数值
-
-
字段 in (数值1,数值2....) 字段的值等于任意一个值就返回结果
-
-- 范围判断 select * from tb_stu where age between 20 and 25; select * from tb_stu where age in(19,22); select * from tb_stu where age not in(19,22);
-
模糊查询
-
字段 like '% _ 数据' % 可以匹配任意多个 _ 匹配任意一个字符
-
字段 rlink '正则表达式'
-
create table tb_stu2( id int, name string, gender string, age int, cls string, email string )row format delimited fields terminated by ','; select * from tb_stu2; -- like的模糊查询 -- 查询姓名为刘的学生 select * from tb_stu where name like '刘%'; -- % 代表任意多个字符 -- 查询姓名为刘的学生 名字个数时2个字的 select * from tb_stu where name like '刘_'; select * from tb_stu where name like '刘__'; -- 查询三个字的 -- rlike 的正则表达式 -- 表的是就是通过不同的符号来表示不同的数据进行匹配 -- \\d 匹配数据的表达式 \\w 匹配字符字母 \\s 匹配空格 select * from tb_stu2; -- ^ 表是什么开头 select * from tb_stu2 where email rlike '^\\d'; -- 表是以数字开头 select * from tb_stu2 where email rlike '^\\w'; select * from tb_stu2 where email rlike '^\\S'; -- ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$ select email,split(email,'@')[1] from tb_stu2; select email,split(split(email,'@')[1],'\\.')[0] from tb_stu2;
-
与或非
-
条件1 and 条件2 and 条件3 ... 多个条件都成立,返回对应的行数据
-
条件1 or 条件2 or 条件3 ... 多个条件满足任意一个,返回对应的行数据
-
-- 与 多个条件都成立 select * from tb_stu; -- 查询性别为男性,学科是is的 select * from tb_stu where gender='男' and cls = 'IS'; -- 查询性别为男性或学科是is的 select * from tb_stu where gender='男' or cls = 'IS';
聚合计算 sum,count
select * from tb_stu; select sum(age) from tb_stu2; select count(*) from tb_stu where name is not null; select avg(age) from tb_stu2; select max(age) from tb_stu; select min(age) from tb_stu;
分组聚合 group by
select sum(age) from tb_stu group by gender; select sum(age),gender from tb_stu group by gender;
注意分组后,select 中不能出现非分组字段
分组后过滤 having
select sum(age),gender from tb_stu group by gender having sum(age)> 200;
排序
order by 全局排序
select * from tb_stu order by age; -- 默认是升序 从小到大 select * from tb_stu order by age desc ; -- 降序 从大到小
分页 limit
-- 分页 select * from tb_stu limit 5; select * from tb_stu limit 10,5; -- 页数 m 每页数量是n (m-1)*n,n
2-2 多表关联查询
join的列关联
-
内关联
-
找关联字段相同的数据
-
-
左关联
-
展示保留左边表的所有数据,右边表有相同数据显示,没有相同数据则为null
-
-
右关联
-
展示保留右边表的所有数据,左边表有相同数据显示,没有相同数据则为null
-
-- table1: 员工表 CREATE TABLE employee( id int, name string, deg string, salary int, dept string ) row format delimited fields terminated by ','; -- table2:员工家庭住址信息表 CREATE TABLE employee_address ( id int, hno string, street string, city string ) row format delimited fields terminated by ','; -- table3:员工联系方式信息表 CREATE TABLE employee_connection ( id int, phno string, email string ) row format delimited fields terminated by ',';
-- on 当成where使用,进行条件顾虑 select * from employee t1 join employee_address t2 on t1.id = t2.id and salary> 30000; select * from employee t1 left join employee_address t2 on t1.id = t2.id; select * from employee t1 right join employee_address t2 on t1.id = t2.id; -- 实现内关联的效果 select * from employee,employee_address where employee.id = employee_address.id;
union的行关联
将select查询计算后的结果表合并
-- union合并 select 'tb_stu',count(*) from tb_stu where name is not null union select 'tb_stu2', count(*) from tb_stu2 where name is not null; -- 保留重复数据 select id,name from tb_stu union all select id,name from tb_stu2;
三、窗口聚合
默认没有窗口函数进行计算时全表数据获取计算
根据指定的窗口范围计算数据,将计算结果单独呈现一列展示,不会因为聚合改变行数
聚合使用,取值函数,排序函数 over(partition by 分组字段 order by 排序字段 rows between 起始行 and 结束行) rows 指定计算的行范围
3-1 聚合窗口
-- 按照性别分组统计年龄和 select sid,sname,age,gander,province,tuition,sum(age) over(partition by gander) from stu; select sid,sname,age,gander,province,tuition,sum(age) over(partition by province,gander) from stu; -- order by 排序后会将前面的数据进行累加 select sid,sname,age,gander,province,tuition,sum(tuition) over(partition by gander order by age) from stu; select sid,sname,age,gander,province,tuition,avg(tuition) over(partition by gander order by age) from stu;
3-2 取值窗口
-- 向上一行取值 select empno,ename,lag(ename) over() from emp; -- 向上两行行取值 select empno,ename,lag(ename,2) over() from emp; -- 去不到值给默认值 select empno,ename,lag(ename,2,'itcast') over() from emp; -- 向下一行取值 select empno,ename,lead(ename) over() from emp; -- 向下两行行取值 select empno,ename,lead(ename,2) over() from emp; -- 去不到值给默认值 select empno,ename,lead(ename,2,'itcast') over() from emp; -- 分组后只进行组内查找 select *,lag(ename) over(partition by job) from emp; -- 取第一个值 select *,first_value(ename)over(partition by job order by sal desc ) from emp;
3-3 排序窗口
按照指定字段排序后生成序号
-- 排序 select *, rank() over (order by sal) as rnk, -- 如果有并列生成序号是不连续的 dense_rank() over (order by sal) as dernk, -- 生成连续序号 row_number() over (order by sal) as rw -- 生成行号 from emp; -- 查找薪资前三 select * from ( select *, dense_rank() over (order by sal desc ) as dernk -- 生成连续序号 from emp) tb1 where dernk <=3;