1 表SQL操作
1.1 通过select数据集创建表
--通过select数据集创建表语法格式
create table table_name [stored as orc]
as
select ......
只能是内部表,不支持分区,分桶
示例:
--创建内部表inner_test1
create table inner_test1 as
select word,num from word_table;
--查看
select count(1) from inner_test1;
1.2 复制一个空表
--只复制表结构,不复制表数据
CREATE TABLE empty_key_value_store LIKE key_value_store;
create table inner_test2 like inner_test1;
1.3 显示表列表
--显示所有表
SHOW TABLES;
--按条件(正则表达式)显示表
SHOW TABLES '.*s';
show tables 'user*';
-- 最通用的写法
show tables like '*user*';
-- 显示函数
show fuctions like '*count*';
1.4 删除表
--删除表
DROP TABLE [IF EXISTS] table_name [PURGE];
说明:
1)对于内部表来说,删除表的操作的本质是删除表的元数据,然后hadoop fs -rm(将表数据挪到回收站目录, .Trash/Current)。
2)如果增加PURGE则不进回收站数据直接删除,不能恢复;
3)对外部表而言只删除元数据, 不删除数据目录,加PURGE也不删。
示例:
drop table inner_test1;
1.5 清除表(只针对内部表)
--清除表
TRUNCATE TABLE table_name [PARTITION partition_spec];
说明:
1)可以删除表和删除分区数据,和drop的区别是不删除元数据(表结构),只删除数据,外部表是不能truncate操作的。
2)外部表不支持使用TRUNCATE语句。
1.6 常用修改表操作
1.6.1 改表名
--改表名
ALTER TABLE table_name RENAME TO new_table_name;
--内部表修改表名
ALTER TABLE user_info RENAME TO user_info_2;
--外部表修改表名
alter table ext_test rename to ext_test_2;
说明:
内部表修改了表名之后,表对应的存储文件地址也跟着改,相当于作了HDFS的目录重命名。
外部表不会改对应的location地址。
内部表重命名
ALTER TABLE inner_test RENAME TO inner_test_c;
hdfs 作了目录重命名
-----------------------------------
外部表重命名
ALTER TABLE ext_test RENAME TO ext_test_c;
1.6.2 修改表属性
ALTER TABLE table_name SET TBLPROPERTIES table_properties;
示例:
alter table ext_test set tblproperties ('comment' = 'EXTERNAL table a!');
1.6.3 增加表分区
内部表增加表分区,自动创建目录。
外部表增加表分区,自动创建目录。
示例:
1)创建分区表:
-- 分区表外部表
CREATE EXTERNAL TABLE ext_task(
word STRING,
num INT
)
PARTITIONED BY (taskname STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
LOCATION '/user/cz45/hive45/ext_task';
-- 分区表内部表
CREATE TABLE inner_task(
word STRING,
num INT
)
PARTITIONED BY (taskname STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
2)添加表分区
-- 分区表外部表添加分区
alter table ext_task add IF NOT EXISTS partition(taskname='wordcount') location 'wordcount';
alter table ext_task add IF NOT EXISTS partition(taskname='maxword') location 'maxword';
alter table ext_task add IF NOT EXISTS partition(taskname='sortword') location 'sortword';
-- 分区表内部表添加分区
alter table inner_task add IF NOT EXISTS partition(taskname='wordcount') location 'wordcount';
alter table inner_task add IF NOT EXISTS partition(taskname='maxword') location 'maxword';
alter table inner_task add IF NOT EXISTS partition(taskname='sortword') location 'sortword';
3)查看表的元数据和表分区元数据
-- 查询具体表的分区目录
select t1.`NAME`, t2.TBL_NAME,t4.PART_NAME, t3.LOCATION from DBS t1, TBLS t2 , SDS t3 , `PARTITIONS` t4
where t1.DB_ID=t2.DB_ID and
t4.SD_ID = t3.SD_ID AND
t2.TBL_ID = t4.TBL_ID and
t1.`NAME` = 'dbname' AND
t2.TBL_NAME like '%task'
UNION
-- 查询具体表的目录
select t1.`NAME`, t2.TBL_NAME,'null', t3.LOCATION from DBS t1, TBLS t2 , SDS t3
where t1.DB_ID=t2.DB_ID and
t2.SD_ID = t3.SD_ID AND
t1.`NAME` = 'dbname' AND
t2.TBL_NAME like '%task' ;
1.6.4 删除分区
--删除表分区的语法格式
ALTER TABLE table_name DROP [IF EXISTS] PARTITION partition_spec[, PARTITION partition_spec, ...];
说明:
内部表删除分区,同时删除分区对应的目录。
外部表删除分区不删除分区对应的目录。
示例:
-- 内部表删除分区
alter table inner_task DROP IF EXISTS partition(taskname='sortword');
-- 外部表删除分区
alter table ext_task DROP IF EXISTS partition(taskname='sortword');
外部表删除:sortword 分区
元数据删除
数据没删除:
1.6.5 修改表或分区的路径
--修改表或分区路径的语法格式
ALTER TABLE table_name [PARTITION partition_spec] SET LOCATION "new location";
说明:
内部表修改分区路径,元数据修改,但hdfs目录没有创建,等导入数据时创建,或者自己主动创建。
外部表修改分区路径,元数据修改,但hdfs目录没有创建,等导入数据时创建,或者自己主动创建。
示例:
--内部表修改分区路径
alter table inner_task PARTITION (taskname='wordcount') set location "hdfs://ns1/hive/warehouse/cz45.db/inner_task/wordcount1";
--外部表修改分区路径
alter table ext_task PARTITION (taskname='wordcount') set location "hdfs://ns1/user/panniu/hive/ext_task/wordcount1";
内部表:
修改分区路径:
导入数据后
-----------------------------
外部表:
修改分区路径:
导入数据后:
结论:无论是外部表还是内部表,修改分区路径,需要自己手动创建路径,或者等导入数据时创建。
1.6.6 分区重命名
--分区重命名语法格式
ALTER TABLE table_name PARTITION partition_spec RENAME TO PARTITION partition_spec;
说明:
如果是内部表,分区重命名,分区对应的地址也会跟着改变,外部表不会。
示例:
--内部表分区重命名会改变分区对应的地址
alter table inner_task partition (taskname='maxword') rename to partition (taskname='maxword01');
--外部表分区重命名不会改变分区对应的地址
alter table ext_task partition (taskname='maxword') rename to partition (taskname='maxword01');
内部表修改分区名称,hdfs目录也修改
外部表修改分区名称,只修改元数据
insert into table ext_task partition(taskname='maxword01')
select word,num from ext_test_c;
maxword01分区导入数据后
1.6.7 增加表字段
--增加表字段、使用新列集合替换现有数据列的语法格式
ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...)
说明:
1)ADD COLUMNS 可以在表列的最后和分区字段前面增加字段。
示例:
1)增加表字段
alter table ext_test_c add columns (test_col string);
--------------------
-- 添加新字段
alter table ext_test_c add columns (col_new string);
-- 导入数据
insert into table ext_test_c
select word,num, 'aaa' from ext_task where taskname='maxword01';
1.6.8 修改表字段
--语法格式
ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]
示例:
alter table ext_test_c CHANGE COLUMN col_new col_new2 string;
2 视图操作
和关系型数据库一样,Hive中也提供了视图的功能,注意Hive中视图的特性,和关系型数据库中的稍有区别:
只有逻辑视图,没有物化视图;
视图只能查询,不能Load/Insert/Update/Delete数据; alter view 和重建效果一致。
视图在创建时候,只是保存了一份元数据,在hdfs中没有体现,当查询视图的时候,才开始执行视图对应的那些子查询,如果子查询比较简单,不会生成MapReduce任务;
--创建视图的语法格式
CREATE VIEW [IF NOT EXISTS] [db_name.]view_name [(column_name [COMMENT column_comment], ...) ]
[COMMENT view_comment]
[TBLPROPERTIES (property_name = property_value, ...)]
AS SELECT ...;
--查看列表
show tables;
-- 查看创建视图的语句
show create table xxx;
说明:
1)视图列和类型可以不指定,如果不指定则有select集合列名和类型决定。
示例:
--原来的SQL, 查询出最多国家的名称和人数
select t1.nn, t2.country from
(select max(a.n) as nn from (
select count(1) n,country from user_install_status_limit group by country
) a) t1
inner join
(select count(1) as n, country from user_install_status_limit group by country) t2
on t1.nn = t2.n;
-- 重复的SQL创建视图
create view tt_country_view
as
select count(1) n,country from user_install_status_limit group by country;
-- 重复的SQL改成视图,结果不变
select t1.maxn, t2.country from
(select max(n) as maxn from tt_country_view
) t1
inner join
tt_country_view t2
on t1.maxn = t2.n;
结论: 无论 使用视图还是不使用视图,执行的任务数不变。主要是为了简化SQL的编写;
3 数据加载
3.1 load 加载数据
如果想用:就用hdfsload, 先添加分区,再导入数据
3.1.1 语法
--load数据加载语法格式
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
说明:
1)hive 的数据加载不会对本地数据文件做任何处理,只是将文件或目录中的所有文件拷贝到表定义的数据目录。
2)filepath 可以是目录,但该目录下不能包含子目录。
3)指定LOCAL本地文件上传,如果没有指定LOCAL,则使用表一样的文件系统 (本地文件不删除)。
4)文件加载hive没有做严格校验,文件格式和压缩选项等匹配需要用户自己保证。
5)分区表要指定具体加载数据分区。
6)如果指定OVERWRITE会覆盖相应表数据或分区数据,相当于 rm 原有目录数据,然后上传新数据文件
HDFS执行MV操作。
-- 以覆盖或追加的方式 , 从linux本地 copy文件到表或表分区里
LOAD DATA LOCAL INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
--以覆盖或追加的方式 , 从hdfs move 文件到表或表分区里
LOAD DATA INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
filepath目录下不能包含子目录
3.1.2 将hdfs中的文件load到表中(move)
需要把 \ext_task 创建出来****
-- 分区表外部表
CREATE EXTERNAL TABLE ext_task(
word STRING,
num INT
)
PARTITIONED BY (taskname STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
LOCATION '/user/panniu/hive30/ext_task';
如果想得到
partition: wordcount01 → /user/panniu/hive31/ext_task/wordcount01
1)先创建分区wordcount01
2)再load数据到表分区wordcount01中
-- 创建分区
alter table ext_task add if not exists partition (taskname='wordcount01') location 'wordcount01';
-- 造数据 上传到 hdfs://ns1/user/panniu/hive26/demo
-- 导入数据
load data INPATH 'hdfs://ns1/user/panniu/hive26/demo' overwrite into table ext_task PARTITION (taskname='wordcount01');
数据导入到了 表的 wordcount01分区
hdfs://ns1/user/panniu/hive26/demo 这个目录,已经mv走了
如果没有创建分区 wordcount02, load时,会自动创建分区目录,目录名为taskname=wordcount02
partition: wordcount02 → /user/panniu/hive/ext_task/taskname=wordcount02
load data INPATH 'hdfs://ns1/user/panniu/hive/data123/word' overwrite into table ext_task PARTITION (taskname='wordcount02');
3.1.3 将本地文件load到表中
--添加partition
alter table ext_task add IF NOT EXISTS partition(taskname='wordcount04') location 'wordcount04';
--本地文件load到表中,相当于将本地文件上传到hdfs中,本地文件不删除
load data local INPATH '/home/panniu/hive_test/word' overwrite into table ext_task PARTITION (taskname='wordcount04');
如果从本地通过load加载数据到hive表,如果用的是into 则分区目录是什么,就将数据放到哪个目录下
但是如果从本地通过load加载数据到hive表,用的是overwrite into ,除非分区目录是分区字段=具体的值(例如age=10),否侧数据不会上传到我们指定的分区目录中,而是hive帮我们新建一个分区目录(分区字段=具体的值)用来存放数据
如果是 从hdfs通过load加载数据到hive表,不管你用的是into还是overwrite into,全部将数据方式指定的分区目录下
taskname=wordcount04
-- 添加分区
alter table ext_task add IF NOT EXISTS partition(taskname='wordcount04') location 'wordcount04';
-- 导入数据
load data local INPATH '/home/panniu/hive_test/ext' overwrite into table ext_task PARTITION (taskname='wordcount04');
元数据也换了
3.2 通过select加载数据
--通过select,将select数据覆盖表或分区的语法格式
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]]
select_statement1 FROM from_statement;
--通过select,将select数据追加到表或分区的语法格式
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)]
select_statement1 FROM from_statement;
说明:
1)当加了 IF NOT EXISTS,如果存在分区就跳过下面的select语句。
2)INSERT OVERWRITE 会覆盖表或分区数据,但覆盖分区时增加IF NOT EXISTS,如果分区已经存在则不会覆盖。
3) INSERT INTO 向表或分区追加数据,不影响历史数据。
示例:
1)将select的数据覆盖到表分区
--添加分区
alter table ext_task add IF NOT EXISTS partition(taskname='wordcount05') location 'wordcount05';
--导入数据
insert overwrite table ext_task partition(taskname='wordcount05')
select
word,
num
from ext_task
where taskname='wordcount01';
2)通过select,将select数据追加到表分区
insert into table ext_task partition(taskname='wordcount05')
select
word,
num
from ext_task
where taskname='wordcount01';
3.3 动态分区
-- 学生表
CREATE TABLE student(
id int,
name string,
age int
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
-- 学生表数据
1 name1 12
2 name2 12
3 name3 13
4 name4 13
5 name5 14
6 name6 14
7 name7 15
8 name8 15
-- 学生分区表
CREATE TABLE student_dyna(
id int,
name string
)
partitioned by (age int)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
-- 需求:把学生表的数据导入的学生分区表中
-- 静态分区导入 适合增量数据的处理
-- 添加12岁的分区,导入12岁数据
alter table student_dyna add IF NOT EXISTS partition(age=12) location '12';
insert overwrite table student_dyna partition(age=12)
select id,name from student where age=12;
-- 添加13岁的分区,导入13岁数据
alter table student_dyna add IF NOT EXISTS partition(age=13) location '13';
insert overwrite table student_dyna partition(age=13)
select id,name from student where age=13;
-- 添加14岁的分区,导入14岁数据
alter table student_dyna add IF NOT EXISTS partition(age=14) location '14';
insert overwrite table student_dyna partition(age=14)
select id,name from student where age=14;
-- 添加15岁的分区,导入15岁数据
alter table student_dyna add IF NOT EXISTS partition(age=15) location '15';
insert overwrite table student_dyna partition(age=15)
select id,name from student where age=15;
------------------------
-- 历史数据导入,不适合静态分区,需要要用动态分区
-- hive默认不开启动态分区
--开启动态分区
set hive.exec.dynamic.partition=true;
--这个属性默认是strict,即限制模式,strict是避免全分区字段是动态的,必须至少一个分区字段是指定有值即静态的,且必
--须放在最前面。设置为nonstrict之后所有的分区都可以是动态的了。
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table student_dyna partition (age)
select id, name, age FROM student;
Hive默认是静态分区,我们在插入数据的时候要手动设置分区,如果源数据量很大的时候,那么针对一个分区就要写一个insert,比如说,有很多我们日志数据,我们要按日期作为分区字段,在插入数据的时候手动去添加分区,那样太麻烦。因此,Hive提供了动态分区,动态分区简化了我们插入数据时的繁琐操作。
--设置参数动态分区
--开启动态分区
set hive.exec.dynamic.partition=true;
--这个属性默认是strict,即限制模式,strict是避免全分区字段是动态的,必须至少一个分区字段是指定有值即静态的,且必
--须放在最前面。设置为nonstrict之后所有的分区都可以是动态的了。
set hive.exec.dynamic.partition.mode=nonstrict;
------------------------------------------------------------------------
--表示每个节点生成动态分区的最大个数,默认是100
set hive.exec.max.dynamic.partitions.pernode=10000;
--表示一个DML操作可以创建的最大动态分区数,默认是1000
set hive.exec.max.dynamic.partitions=100000;
--表示一个DML操作可以创建的最大文件数,默认是100000
set hive.exec.max.created.files=150000
--将select数据,覆盖到表的动态分区
insert overwrite table table1 partition (ds, hr)
select key, value, ds, hr FROM table2 WHERE ds is not null;
建议不将表的所有字段做全分区字段,建议指明分区名,然后再插入数据。
动态分区:分区 字段值必须是有限,可控的。
应用场景:已经有表,然后,有需求需要把原来表按照某个字段进行分区统计时,导入时,可以 开启动态分区一次性导入数据。
示例:
开启动态分区导入分区表
设置开启分区
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
查询数据动态插入student_dyna表
insert overwrite table student_dyna
partition(age)
select
id,
name,
age
from student;
4 将数据写入文件系统
4.1 将数据写入一个文件
查询表数据导出到某个文件【linux本地/ hdfs】
--语法格式
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
[ROW FORMAT row_format] [STORED AS file_format]
SELECT ... FROM ...
示例:
1)将select的数据写入到hdfs文件中,多层目录会帮你创建
-- 查询ext_task 表中分区为wordcount 的数据,以AVRO 格式写入到hdfs指定目录
insert overwrite directory 'hdfs://ns1/user/panniu/hive26/export_data/d1_avro' STORED AS AVRO
select word, num from ext_task where taskname='wordcount01';
如果是分区表,导出所有数据时,导出的格式是avro、orc文件格式,如果不加分区导出时,会报错。
但是如果给linux本地导数据,导出的格式是avro、orc文件格式不加分区也不会报错。
insert overwrite directory 'hdfs://ns1/user/panniu/hive26/export_data/d2_avro' STORED AS AVRO
select word, num from ext_task;
如何把分区表中所有数据都导出来avro、orc文件格式
需要通过临时表,作为中间表,先导出到中间表,再从中间表导出avro、orc文件格式的数据。
-- 创建临时中间表s
CREATE TEMPORARY TABLE `task_tmp`(
word string,
num int)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
-- 先导出到中间表
insert into table task_tmp
select word, num from ext_task;
-- 再从中间表导出文件
insert overwrite directory 'hdfs://ns1/user/panniu/hive/data456/d2_avro' STORED AS AVRO
select word, num from task_tmp;
2)将select的数据写入到本地文件中, 多层目录会自动帮你创建
-- 查询ext_task 表中分区为wordcount 的数据,以text 格式写入到本地目录中
insert overwrite local directory '/home/panniu/hive_test/d1_text'
select word, num from ext_task where taskname='wordcount01';
分区表不加分区导出到linux本地不报错。
insert overwrite local directory '/home/panniu/hive_test/d2_avro' STORED AS AVRO
select word, num from ext_task;
4.2 将数据写入多个文件
--语法格式
FROM from_statement
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 row_format
select_statement1 where
[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 row_format
select_statement2 where ] ...
row_format
: DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]
[MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
[NULL DEFINED AS char]
说明:
1)导出到文件系统的数据都序列化成text,非原始类型字段会序列化成json,导出文件以^A分隔 \n结尾的文本数据。
2)INSERT OVERWRITE 到HDFS目录,可以通过MR job实现并行写入。这样在集群上抽取数据不仅速度快,而且还很方便。
3)批量导出多个文件,需要导出文件的类型一致,如果一个是avro,一个是text,报错。
示例:
从一张表中导出两个文件到不同的路径
分区表:需要两个分区一致,在一个分区下,来导出不同条件的数据
from ext_task
insert overwrite directory 'hdfs://ns1/user/panniu/hive26/output_avro5' STORED AS AVRO
select
word,
num
where taskname='wordcount01' and word='aa'
insert overwrite local directory '/home/panniu/hive_test/output_avro4' STORED AS AVRO
select
word,
num
where taskname='wordcount01' and word='bb';
不是分区表:
在表下,导出不同条件的数据
from student
insert overwrite directory 'hdfs://ns1/user/panniu/hive/output_avro5' STORED AS AVRO
select
id,name
where age=12
insert overwrite local directory '/home/panniu/hive_test/0403/output_avro4' STORED AS AVRO
select
id,name
where age=13
如果多个输出目录,导出的格式不同,也报错。
报错例子:
from ext_task
insert overwrite directory 'hdfs://ns1/user/panniu/hive/output_avro5' STORED AS Textfile
select
word,
num
where taskname='wordcount04'
insert overwrite local directory '/home/panniu/hive_test/0403/output_avro4' STORED AS AVRO
select
word,
num
where taskname='wordcount04';
4.3 hive -e 执行命令 导出
-- 导出数据
hive -e "use c26pan;select word,num from ext_task where taskname='wordcount01';" > ./output_txt4
-- 后台运行,关心错误信息,输出到某个文件里
nohup hive -e "use c26pan;select word,num from ext_task where taskname='wordcount01' ;" 1> ./output_txt5 2>./err.log &
-- 后台运行,错误信息不关心,放到无底洞里
nohup hive -e "use c26pan;select word,num from ext_task where taskname='wordcount01' ;" 1> ./output_txt6 2>/dev/null &
4.4 hive -f 执行SQL文件 导出
[panniu@op 03]$ vim hivesql.sql
use c31pan; select * from ext_task where taskname='wordcount01';
hive -f hivesql.sql > output_data2