Apache Hive SQL
进入Hive流程
-
启动matastore服务 --脚本
-
启动hiveserver2服务 --脚本
-
检测 --jps (两个RunJar 启动)
-
beeline客户端连接--
[root@node1 ~]# /export/server/hive-3.1.2/bin/beeline beeline> ! connect jdbc:hive2://node1:10000 beeline> root beeline> 直接回车 0: jdbc:hive2://node1:10000> show databases; +----------------+ | database_name | +----------------+ | default | +----------------+ 1 row selected (1.242 seconds)
Hive SQL --DDL--建表
create table 表名
creat table if not exists 表名 --加上if not exists 忽略异常
Hive的数据类型
Hive 支持SQL类型外,还支持java数据类型,还支持复合类型(array数组 map映射)
在建表的时候,最好表的字段类型要和文件中的类型保持一致(如果不一致,Hive 会尝试进行类型隐式转换,不保证转换成功,不成功会显示null值)
--案例 --创建数据库并切换使用 create database if not exists itheima; use itheima; --建表 create table t_archer( id int comment "ID", name string comment "英雄名称",--comment 说明 hp_max int comment "最大生命", mp_max int comment "最大法力", attack_max int comment "最高物攻", defense_max int comment "最大物防", attack_range string comment "攻击范围", role_main string comment "主要定位", role_assist string comment "次要定位" ) comment "王者荣耀射手信息" row format delimited --行格式分隔 fields terminated by "\t";--字段终止与
comment 说明
row 行;format 格式;delimited 限定
fields 字段;terminated 终止
查看表的元数据信息
desc formatted 表名
--查看表数据 查看表的元数据信息 select * from t_archer; desc formatted t_archer;
formatted 格式化
上传文件到表对应的HDFS目录下
-- todo 加载数据 方式一 local inpath 从linux中加载, 复制效果 load data local inpath '/root/data/01_archer.txt' into table db_2.tb_archer;-- todo 加载数据 方式二 inpath 从 hdfs中加载, 剪切效果, load data inpath '/67_archer.txt' into table db_2.tb_archer; -- todo 注意: cdh(理解 hadoop的发行版)中 只支持 load data inpath-- todo 加载数据 方式三 [root@node1 data]# hdfs dfs -put 01_archer.txt /user/hive/warehouse/db_2.db/tb_archer
Hive读写HDFS上文件
--创建表 --表后面增加 字段之间的分隔符 或 指定map类型kv之间的分隔符--上传文件
分割符
ROW FORMAT DELIMITED具体的子语法
row format delimited
表示使用LazySimpleSerDe类进行序列化解析数据
fields terminated by ','
指定字段之间的分隔符collection items terminated by '-'
指定集合元素之间的分隔符map keys terminated by ':'
指定map类型kv之间的分隔符默认分隔符 \001默认分隔符
--案例: --第一步 建表 create table t_hot_hero_skin_price( id int, name string, win_rate int, skin_price map<string,int> ) row format delimited fields terminated by ',' --字段之间分隔符 collection items terminated by '-' --集合元素之间分隔符 map keys terminated by ':'; --集合元素kv之间分隔符; --第二步 上传数据 --方式一 linux上操作 上传文件 hadoop fs -put hot_hero_skin_price.txt /user/hive/warehouse/itheima.db/t_hot_hero_skin_price ; --方式二 hive本地加载Linux文件 load data local inpath '/root/data/hot_hero_skin_price.txt' into table t_hot_hero_skin_price ;
内部表,外部表
表的组成:元数据+数据文件
内部表:删除的时候,既要删除元数据,又要删除 数据文件,应用场景:部门内部操作的文件.
外部表:删除的时候,只删除元数据,数据文件本身不删除,应用场景:多个不同部分共享的文件
--创建内部表 create table student_inner( Sno int, Sname string, Sex string, Sage int, Sdept string) row format delimited fields terminated by ',';
--创建外部表关键字external--
--创建外部表 关键字--external-- create external table student_external( Sno int,Sname string,Sex string,Sage int,Sdept string) row format delimited fields terminated by ',';
--内部表 在删除的时候 元数据和数据都会被删除
--外部表 在删除的时候 只删除元数据 而HDFS上的数据文件不会动
外部表有什么好处最大的好处是防止误操作删除表的时候 把表的数据一起删除.
可以通过desc formatted table_name;
去查询表的元数据信息 获取表的类型
desc formatted table_name; MANAGED_TABLE 内部表、受控表 EXTERNAL_TABLE 外部表
表数据在HDFS上储存路径
储存路径由 hive.metastore.warehouse.dir 属性指定.默认值是:/user/hive/warehouse
不管是内部表,还是外部表,在HDFS上的路径如下: /user/hive/warehouse/itcast.db/t_array /user/hive/warehouse/数据库名.db/表名
Hive的分区表
-创建表(partitioned by(**))-分区表的数据加载(静态分区加载/动态分区加载)-分区表使用
分区表的创建
partitioned by()
--分区表建表 create table t_all_hero_part( id int, name string, hp_max int, mp_max int, attack_max int, defense_max int, attack_range string, role_main string, role_assist string ) partitioned by (role string)--注意哦 这里是分区字段 分区字段不能与表字段重复 row format delimited fields terminated by "\t";
静态分区表的数据加载
--静态加载分区表数据 load data local inpath '/root/hivedata/archer.txt' into table t_all_hero_part partition(role='sheshou'); load data local inpath '/root/hivedata/assassin.txt' into table t_all_hero_part partition(role='cike'); load data local inpath '/root/hivedata/mage.txt' into table t_all_hero_part partition(role='fashi'); load data local inpath '/root/hivedata/support.txt' into table t_all_hero_part partition(role='fuzhu'); load data local inpath '/root/hivedata/tank.txt' into table t_all_hero_part partition(role='tanke'); load data local inpath '/root/hivedata/warrior.txt' into table t_all_hero_part partition(role='zhanshi'); --查询一下验证是否加载成功 select * from t_all_hero_part;
动态分区加载
设置允许动态分区、设置动态分区模式
--动态分区 set hive.exec.dynamic.partition=true; --注意hive3已经默认开启了 set hive.exec.dynamic.partition.mode=nonstrict; --模式分为strict严格模式 nonstrict非严格模式 严格模式要求 分区字段中至少有一个分区是静态分区。
动态分区加载数据
格式:insert into table 加载的表名 partition(分区名) select *,原表.字段名 from 原表名
插入的数据来自于后面的查询语句返回的结果。
查询返回的内容,其字段类型、顺序、个数要和待插入的表保持一致。
--创建一张新的分区表 t_all_hero_part_dynamic create table t_all_hero_part_dynamic( id int, name string, hp_max int, mp_max int, attack_max int, defense_max int, attack_range string, role_main string, role_assist string ) partitioned by (role string) row format delimited fields terminated by "\t"; --执行动态分区插入 --注意 分区值并没有手动写死指定 insert into table --insert into table t_all_hero_part_dynamic --向那张表加载 partition(role) --partition(分区名字) select tmp.*,--select * tmp.role_main --被加载表名.对应字段 from t_all_hero tmp;--from 被加载的表名 --查询验证结果 select * from t_all_hero_part_dynamic;分区表的使用
--非分区表 全表扫描过滤查询 select count(*) from t_all_hero where role_main="archer" and hp_max >6000; --分区表 先基于分区过滤 再查询 select count(*) from t_all_hero_part where role="sheshou" and hp_max >6000;
分区表注意事项
-
分区表的字段不能是表中已有的字段
-
以文件夹管理不同的文件
-
创建分区表之后,使用分区字段查询可以减少全表扫描,提高查询的效率
多重分区表
多重分区表之间是一种递进关系,可以理解为前一个分区的基础上继续分区 ,常见的多分区就是2个分区.
--创建表 create table t_user_double_p(id int,name string,country string) partitioned by --固定格式 (guojia string,sheng string) --分区1 类型,分区2 类型 row format delimited fields terminated by ','; --加载数据到多分区表中 load data local inpath --本地加载固定格式 '/root/hivedata/china_sh.txt' --文件地址 into table t_user_double_p -- partition(guojia="zhongguo",sheng="shanghai");--partition(分区1='',分区2='') load data local inpath '/root/hivedata/china_sz.txt' into table t_user_double_p partition(guojia="zhongguo",sheng="shenzhen"); load data local inpath '/root/hivedata/usa_dezhou.txt' into table t_user_double_p partition(guojia="meiguo",sheng="dezhou"); --查询来自于中国深圳的用户有哪些? select * from t_user_double_p where guojia="zhongguo"and sheng="shenzhen";
Hive分桶表
从语法层面解析分桶含义
CLUSTERED BY xxx INTO N BUCKETS --根据xxx字段把数据分成N桶 --根据表中的字段把数据文件成为N个部分 t_user(id int,name string); --1、根据谁分? CLUSTERED BY xxx ; xxx必须是表中的字段 --2、分成几桶? N BUCKETS ;N的值就是分桶的个数 --3、分桶的规则? clustered by id into 3 bucket hashfunc(分桶字段) % N bucket 余数相同的来到同一个桶中 1、如果分桶的字段是数字类型的字段,hashfunc(分桶字段)=分桶字段本身 2、如果分桶的字段是字符串或者其他字段,hashfunc(分桶字段) = 分桶字段.hashcode
分桶表创建
--创建表 --根据state州分为5桶 每个桶内根据cases确诊病例数倒序排序 CREATE TABLE itheima.t_usa_covid19_bucket_sort( count_date string, county string, state string, fips int, cases int, deaths int) CLUSTERED BY(state)--根据(state)进行分桶 sorted by (cases desc) --根据(cases 倒序) INTO 5 BUCKETS;--into 分 5 桶
分桶表的数据加载
--step1:开启分桶的功能 从Hive2.0开始不再需要设置 set hive.enforce.bucketing=true; --step2:把源数据加载到普通hive表中 CREATE TABLE itheima.t_usa_covid19( count_date string, county string, state string, fips int, cases int, deaths int) row format delimited fields terminated by ","; --将源数据上传到HDFS,t_usa_covid19表对应的路径下 hadoop fs -put us-covid19-counties.dat /user/hive/warehouse/itheima.db/t_usa_covid19 --step3:使用insert+select语法将数据加载到分桶表中 insert into t_usa_covid19_bucket select * from t_usa_covid19; select * from t_usa_covid19_bucket;
分桶表的使用
--基于分桶字段state查询来自于New York州的数据 --不再需要进行全表扫描过滤 --根据分桶的规则hash_function(New York) mod 5计算出分桶编号 --查询指定分桶里面的数据 就可以找出结果 此时是分桶扫描而不是全表扫描 select * from t_usa_covid19_bucket where state="New York";
分桶的总结
-
分桶表也是一种优化表,可以减少join查询时笛卡尔积的数量、提高抽样查询的效率。
-
分桶表的字段必须是表中已有的字段;
-
分桶表需要使用间接的方式才能把数据加载进入:insert+select
-
在join的时候,针对join的字段进行分桶,可以提高join的效率 减少笛卡尔积数量。
Hive SQL--DDL其他操作
Database 数据库 DDL操作
建库
--建库 create database if not exists db_7 comment '电商库' --commont注释名字 with dbproperties('createdBy'='zhangsan')--设置键值对属性值;
看数据库属性
-- 查看库的描述信息 desc database db_7; -- 查看库的详细描述信息 desc database extended db_7;-- 查看库的详细描述信息 desc database extended db_7;
更改数据库属性
--更改数据库属性 alter database db_7 set dbproperties ('createBy'='list_1')
更改数据库所有者
alter database db_7 set owner user user_1;
更改数据库位置
alter database db_7 set location 'hdfs://node1:8020/bj_67';
表结构的操作
删除表
drop table if exists db_7.tb_student;
查看表的详细信息
-- todo 2 查看建表语句 show create table db_4.t_user;
更改表的注释
-- todo 3 更改表的注释 alter table db_4.t_user set tblproperties('comment'='this is qq info table'); show create table db_4.t_user;
更改表的存储位置
alter table db_4.t_user set location '/test/data/t_user_2';
更改列的名称/类型
CREATE TABLE t1_change (a int, b int, c int); alter table t1_change change b b1 string;
Partition 分区 DDL操作
比较重要的是增加分区 ,删除分区 操作
增加分区--创建分区表--load加载
--创建数据库 create database if not exists db_8; use db_8; --创建 含有分区的表 create table db_8.tb_student_partition ( id int, name string, sex string, age int, dept string ) partitioned by (dt string) row format delimited fields terminated by ','; --linux 本地加载数据 partition 数据 load data local inpath '/root/data/students.txt' into table db_8.tb_student_partition partition (dt='2023-01-01'); --在linux系统添加分区 向分区内 上传表 hdfs dfs -mkdir -p /user/hive/warehouse/db_8.db/tb_student_partition/dt=2023-01-02 hdfs dfs -put /root/data/04_students.txt /user/hive/warehouse/db_8.db/tb_student_partition/dt=2023-01-02
增加分区表
--在现有的分区表,增加新分区 alter table db_8.tb_student_partition add partition (dt='2023-01-03');
查看表内的分区
--查看表内的分区 show partitions db_8.tb_student_partition;
修改表内分区
--修改分区 alter table db_8.tb_student_partition partition (dt='2023-01-03') rename to partition (dt='2023-06-01');
删除表内分区
--删除分区 alter table db_8.tb_student_partition drop partition (dt='2023-06-01');
查询
--1、显示所有数据库 SCHEMAS和DATABASES的用法 功能一样 show databases; show schemas;--2、显示当前数据库所有表/视图/物化视图/分区/索引 show tables; SHOW TABLES [IN database_name]; --指定某个数据库--3、显示当前数据库下所有视图 --视图相当于没有数据临时表 虚拟表 Show Views; SHOW VIEWS 'test_*'; -- show all views that start with "test_" SHOW VIEWS FROM test1; -- show views from database test1 SHOW VIEWS [IN/FROM database_name];--4、显示当前数据库下所有物化视图 SHOW MATERIALIZED VIEWS [IN/FROM database_name];--5、显示表分区信息,分区按字母顺序列出,不是分区表执行该语句会报错 show partitions table_name; show partitions itheima.student_partition; show partitions db_8.tb_student_partition;--6、显示表/分区的扩展信息 SHOW TABLE EXTENDED [IN|FROM database_name] LIKE table_name; show table extended like student; describe formatted itheima.student; desc formatted db_8.tb_student_partition;--7、显示表的属性信息 SHOW TBLPROPERTIES table_name; show tblproperties student;--8、显示表、视图的创建语句 SHOW CREATE TABLE ([db_name.]table_name|view_name); show create table student; show create table db_8.tb_student_partition;--9、显示表中的所有列,包括分区列。 SHOW COLUMNS (FROM|IN) table_name [(FROM|IN) db_name]; show columns in student; show columns in db_8.tb_student_partition; desc db_8.tb_student_partition; --10、显示当前支持的所有自定义和内置的函数 show functions;--11、Describe desc --查看表信息 desc extended table_name; --查看表信息(格式化美观) desc formatted table_name; --查看数据库相关信息 describe database database_name;
load 重点
create table db_9.tb_student_linux( id int, name string, sex string, age int, dept string ) row format delimited fields terminated by ',' ; -- 目标1: 使用load 从 linux的文件 加载数据 load data local inpath '/root/data/students.txt' into table db_9.tb_student_linux; select * from tb_student_linux; create table db_9.tb_student_hdfs( id int, name string, sex string, age int, dept string ) row format delimited fields terminated by ','; -- 目标2: 使用load 从 hdfs的文件 加载数据 hdfs dfs -put /root/data/04_students.txt /bj_67 load data inpath '/bj_67/students.txt' into table db_9.tb_student_hdfs; select * from tb_student_hdfs;create table db_9.tb_student_linux_partition( id int, name string, sex string, age int, dept string ) partitioned by (dt string) row format delimited fields terminated by ','; -- 目标3: 使用load 向分区表 加载数据 load data local inpath '/root/data/04_students.txt' into table tb_student_linux_partition partition(dt='2023-01-01'); select * from tb_student_linux_partition; load data local inpath '/root/data/04_students.txt' into table tb_student_linux_partition partition(dt='2023-01-01'); select * from tb_student_linux_partition; load data local inpath '/root/data/04_students.txt' overwrite into table tb_student_linux_partition partition(dt='2023-01-01'); select * from tb_student_linux_partition;
覆盖效果 overwrite
-- 目标4: 覆写效果 -- todo 问题: 覆写 就旧的都删掉, 将新的放进去 对不对? load data local inpath '/root/data/04_students.txt' into table tb_student_linux_partition partition(dt='2023-01-01'); load data local inpath '/root/data/04_students.txt' into table tb_student_linux_partition partition(dt='2023-01-02'); load data local inpath '/root/data/04_students.txt' into table tb_student_linux_partition partition(dt='2023-01-03'); load data local inpath '/root/data/04_students.txt' overwrite into table tb_student_linux_partition partition(dt='2023-01-01');
insert_select
-- 准备工作 create database if not exists db_10; use db_10; create table db_10.tb_student( id int, name string, sex string, age int, dept string ) row format delimited fields terminated by ','; load data local inpath '/root/data/04_students.txt' into table db_10.tb_student; create table db_10.tb_student_2( id int, name string, sex string, age int, dept string ) row format delimited fields terminated by ','; drop table if exists db_10.tb_student_partition; create table db_10.tb_student_partition( id int, name string, sex string, age int, dept string ) partitioned by (dept_info string) row format delimited fields terminated by ','; select * from tb_student;-- 目标1 使用 insert + select 向普通表插入数据 insert into db_10.tb_student_2 select * from tb_student where dept in ('IS', 'CS'); select * from tb_student_2;-- 目标2 使用 insert + select 向分区表插入数据 insert into db_10.tb_student_partition partition(dept_info) select id, name, sex, age, dept, dept as dept_info from tb_student where dept in ('IS', 'CS'); -- 注意: 分区列 应该放到 普通列的后面 且 跟建表的列的顺序保持一致 select * from tb_student_partition;-- 目标3 使用 insert overwrite + select 向普通表插入数据 insert overwrite table db_10.tb_student_2 select * from tb_student where age>18;-- 目标4 使用 insert overwrite + select 向分区表插入数据 set hive.exec.dynamic.partition.mode=nonstrict; insert overwrite table db_10.tb_student_partition partition(dept_info) select id, name, sex, age, dept, dept as dept_info from tb_student where dept in ('IS', 'MA') and age>20;
多重插入
-- todo 目标: 多重插入 -- todo 1 创建表1 create table db_10.tb_student_3( id int, name string ); -- todo 2 创建表2 create table db_10.tb_student_4( id int, dept string ); -- todo 3 分解式 插入数据 insert into db_10.tb_student_3 select id, name from db_10.tb_student; insert into db_10.tb_student_4 select id, dept from db_10.tb_student; -- todo 问题: 多次插入 都需要 扫描同一个表? -- todo 解决: 多次插入 只需要 扫描一次 -- todo 清空表的内容 truncate table db_10.tb_student_3; truncate table db_10.tb_student_4; -- todo 4 合并式 插入数据 from db_10.tb_student insert into db_10.tb_student_3 select id, name insert into db_10.tb_student_4 select id, dept;
导出
-- todo 目标: 导出 select * from db_10.tb_student where sex='女'; -- todo 1 将内容导出到 hdfs中 且 不指定分隔符 insert overwrite directory '/export_data/s1' select * from db_10.tb_student where sex='女'; -- todo 2 将内容导出到 hdfs中 且 指定分隔符 insert overwrite directory '/export_data/s2' row format delimited fields terminated by '*' select * from db_10.tb_student where sex='男'; -- todo 3 将内容导出到 本地linux中 且 指定分隔符 insert overwrite local directory '/export_data/s3' row format delimited fields terminated by '*' select * from db_10.tb_student where age>18; -- todo 4 将内容导出到 本地linux中 且 指定分隔符 且 指定默认的存储方式 insert overwrite local directory '/export_data/s4' row format delimited fields terminated by '*' stored as orc select * from db_10.tb_student where age>18;
分页
分页的语法: limit x,y x表示 从哪个下标开始, 从0开始, y表示 长度
分组
group by
分桶查询
-- 目标: 分桶查询 -- todo 方式一: cluster by xxx 含义: 根据指定列分 且 按照指定列 正序 -- 默认情况下, 将结果放到一个文件中 insert overwrite local directory '/root/export_data/s1' select * from db_10.tb_student cluster by id; -- 默认情况下, 将结果放到二个文件中 set mapreduce.job.reduces; set mapreduce.job.reduces = 2; -- todo 如果想分成多部分, 这个是必须得 insert overwrite local directory '/root/export_data/s2' select * from db_10.tb_student cluster by id; -- todo 需求: 根据指定列分 且 按照指定列 正序 -- todo 方式二 cluster by id 等价于 distribute by id sort by id asc insert overwrite local directory '/root/export_data/s3' select * from db_10.tb_student distribute by id sort by id asc; -- todo 需求: 根据指定列分 且 按照指定列 降序 insert overwrite local directory '/root/export_data/s4' select * from db_10.tb_student distribute by id sort by id desc; -- todo 需求: 根据id分 且 按照年龄 降序 insert overwrite local directory '/root/export_data/s5' select * from db_10.tb_student distribute by id sort by age desc;
union 上下表合并
-- todo 目标: union的用法 -- todo 需求1: 1 查询大于18岁的人 2 查询大于20岁的人 3 将1和2整合到一起 select * from db_10.tb_student where age>18; -- 15人 select * from db_10.tb_student where age>20; -- 5人 -- union all 不会去重 select * from db_10.tb_student where age>18 union all select * from db_10.tb_student where age>20; -- union distinct 去重 select * from db_10.tb_student where age>18 union distinct select * from db_10.tb_student where age>20; -- union 去重 和 不去重? 去重 union 等价于 union distinct select * from db_10.tb_student where age>18 union select * from db_10.tb_student where age>20; -- union 注意事项: 上下的结果 列的数量和类型 必须一致
cte的用法
-- todo 目标: cte用法 (代替 子查询) -- todo 需求: 查询 部门为 IS 且 年龄 > 18 的 男生和女生各多少人 -- todo 方式一: 采用子查询 select * from db_10.tb_student where dept='IS'; select * from (select * from db_10.tb_student where dept='IS') t1 where age>18; select sex, count(1) as cnt from (select * from (select * from db_10.tb_student where dept='IS') t1 where age>18) t2 group by sex; -- todo 需求: 查询 部门为 IS 且 年龄 > 18 的 男生和女生各多少人 -- todo 方式二: 采用 CTE with t1 as ( select * from db_10.tb_student where dept='IS' ), t2 as ( select * from t1 where age>18 ) select sex, count(1) as cnt from t2 group by sex;