一、DML : Data Manipulation Language
1.加载数据到表:
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
---LOCAL本地的意思,这里是指linux系统,如果没有LOCAL,就指hdfs
根据dept.txt
a. 创建表ruoze_dept
create table ruoze_dept(
deptno int,
dname string,
loc string
)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
b.导入数据
LOAD DATA LOCAL INPATH '/home/hadoop/data/dept.txt' INTO TABLE ruoze_dept; #这里没加overwrite
load data local inpath '/home/hadoop/data/dept.txt' overwrite into table ruoze_dept; #这里加了overwrite
c.查询一下数据
以hdfs的方式load
先把数据put 到hdfs上,hadoop fs -put ‘/home/hadoop/data/dept.txt’ /data
跟着LOAD DATA INPATH '/data/dept.txt' INTO TABLE ruoze_dept; #因为是用hdfs,所以不需要添加local关键字。
最后可以用select * from ruoze_dept; 查询一下。
注意:用hdfs的方式,load一次后,如果再load一次相同的文件时就会报错
因为是用内部表,hdfs上的dept.txt移动到目标地方,相同于mv了,所以hdfs就已经没有dept.txt这个文件了.
2.以SQL插入数据
Standard syntax:
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;
INSERT OVERWRITE TABLE ruoze_emp_test select empno,ename from ruoze_emp;
# 这个语句中,select 后面的字段个数跟ruoze_emp_test的字段个数不一样。
INSERT OVERWRITE TABLE ruoze_emp_test
select empno,job,ename,mgr,hiredate,sal,comm,deptno from ruoze_emp;
#这个语句中,select后面的字段位置错位了,执行时是可以运行的,但是结果是不对的,所以要注意。
另:要注意不要用下面这种插入数据的方式,因为大量的数据,不可能一条一条插入
INSERT INTO TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row ...] ;
同理,下面update和delete的方式也不要用。
UPDATE tablename SET column = value [, column = value ...] [WHERE expression];
DELETE FROM tablename [WHERE expression];
3.导出数据
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/ruoze'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
SELECT empno,ename FROM ruoze_emp; #跟前面的一样,有local关键字表示写入本地(即linux),不添加local关键字表示写入hdfs
可以进去/tmp/ruoze这个路径看看是否有数据
二.DML的查询相关的内容以及函数
我们说 Hive是构建在Hadoop之上的数据仓库
那么,sql ==> Hive ==> MapReduce,(sql提交到hive后,转化成MP执行的),那么好像下面的有转化成MP作业吗?是没有的。这个简单的是没有的。
1.聚合函数: max min sum avg count
对于聚合函数的语句,是会跑MP作业的。
2.分组函数,出现在select中的字段,要么出现在group by子句中,要么出现在聚合函数中,叫叫做分组函数。
求部门的平均工资
求每个部门、工作岗位的最高工资
求每个部门的平均薪水大于2000的部门
select deptno,avg(sal) from ruoze_emp group by deptno having avg(sal)>2000;
#要注意having 要用在group by 后面。
3.case when then 类似于 if-else
select ename, sal,
case
when sal>1 and sal<=1000 then 'LOWER'
when sal>1000 and sal<=2000 then 'MIDDLE'
when sal>2000 and sal<=4000 then 'HIGH'
ELSE 'HIGHEST' end
from ruoze_emp;
4.union和union all
select count(1) from ruoze_emp where deptno=10
union all
select count(1) from ruoze_emp where deptno=20;
union可以用在数据倾斜,比如a1是不倾斜的,a2表是倾斜的,把正确的捞出来,不正确的也捞出来,最后union
a = a1 union all a2
5.那这么多内置函数,怎么查出来hive所支持的内置函数呢?
可以用desc functions,如果是具体的某一函数比如upper的用法,可以用
desc function extended upper;来查询一下。
但有些内置函数用desc function是查不出来,比如cast,
cast(value as TYPE) 如果转换失败,返回值就是null。
另外截取字符串substring、拼接字符串concat、concat_wc、切割函数split也是常用的
explode行转列函数的使用,现在看看下面这个内容,假如有3个学生,有对应的选修的科目,但是他们选的科目是一个数组
1,doudou,化学:物理:数学:语文
2,dasheng,化学:数学:生物:生理:卫生
3,rachel,化学:语文:英语:体育:生物
a.根据上面的信息,在 '/home/hadoop/data/' 新建student.txt
b.建表
create table ruoze_student(
id int,
name string,
subjects array
)row format delimited fields terminated by ','
COLLECTION ITEMS TERMINATED BY ':'; #集合里面的分隔符是用 : 号
c.导入(上传)数据
load data local inpath '/home/hadoop/data/student.txt' into table ruoze_student;
d.查询一下,select * from ruoze_student; # 有3列,注意第三列是一个数组集合
e.用行转列函数explode
select distinct s.sub from (select explode(subjects) sub from ruoze_student) s
意思是先select explode(subjects) sub from ruoze_student查出来,再distinct去重。
6.需求:使用hive完成wordcount (hive和spark的wordcount统计在面试时会经常考)
a.create table ruoze_wc(
sentence string
);
b.在/home/hadoop/data建立wc.txt
hello,world,welcome
hello,world
hello,welcome
c.导入数据到hive
load data local inpath ‘/home/hadoop/data/wc.txt’ overwrite into table ruoze_wc ;
d.执行sql
select word, count(1) as c
from
(
select explode(split(sentence,",")) as word from ruoze_wc
) t
group by word
order by c desc;
split是分割数组,explode是行转列,count(1)作统计。见下图,已经完成wordcount。
三、分区表
1、分区表简介和一级分区
除了内部表、外部表,还有分区表。
什么是分区表呢?分区表:一个表按照某个字段进行分区
那分区的意义何在呢?举个例子
access.log –--是数据量很大的一个日志
要求查该日子startime>201810212200 and starttime < 201810212359
这样查性能很低。
所以需要做分区:
比如要查20181021这一天的数据,就不需要查其它日期的数据
/user/hive/warehouse/access/d=20181021
先创建分区表
create table order_partition(
orderNumber string,
event_time string
)PARTITIONED BY(event_month string)
row format delimited fields terminated by '\t'; #创建分区表时,是需要添加关键字partitioned
导入数据
load data local inpath '/home/hadoop/data/order.txt' into table order_partition PARTITION (event_month='2014-05'); # 平常普通表不用PARTITION的,但分区表要加PARTITION
注意:如果load数据时有字符集的问题,可以按照下面的方法修改
use ruoze_d5;
alter table PARTITIONS convert to character set latin1;
alter table PARTITION_KEYS convert to character set latin1;
然后可以去hdfs上看看(在hdfs上分区表也是一个目录,一个分区对应一个目录),目录的名字有点特殊的,它是采用
分区字段=分区值,所以以后看到这种结构,就是分区表。
hadoop fs -ls /user/hive/warehouse/d5_hive.db/order_partition
既然我们知道规则和道理了,那我们再建一个分区表event_month=2014-06,
hadoop fs -mkdir /user/hive/warehouse/d5_hive.db/order_partition/event_month=2014-06
将数据put到hdfs的分区上
hadoop fs -put order.txt
/user/hive/warehouse/d5_hive.db/order_partition/event_month=2014-06
查一下是否有数据 select * from order_partition where event_month='2014-06';
结果是没有数据。原因是元数据里面没有数据。
我们可以刷新一下分区,用msck repair table order_partition;
现在再来查询一下,分区event_month='2014-06'已经有数据了
因为这个命令会把 2014-06的信息从MySQL表里面刷新,从而可以再Hive上查询表可以查询的到信息同步过来了。但有一个致命的缺点,它会把刷新所有MySQL表里面的信息,性能会非常低。所以杜绝用msck repair table order_partition;
可以用alter table …add …解决,在生产上用这种刷新的方式。现在来试试:
我们创建一个新的分区表,把本地的数据放到hdfs分区表event_month=2014-07的上面。
新创建一个分区表:
hadoop fs -mkdir /user/hive/warehouse/d5_hive.db/order_partition/event_month=2014-07
将数据put到hdfs的分区上:
hadoop fs -put order.txt
/user/hive/warehouse/d5_hive.db/order_partition/event_month=2014-07/
现在查分区表是没有的,就用
alter table order_partition add if not exists partition(event_month='2014-07');
现在查一下有数据了。
查询一个表有多少个分区
用:show partitions order_partition;
2.多级分区
在hive或spark SQL生产上,我们一般是多级分区用得比较多。
再创建一个分区
create table order_mulit_partition(
orderNumber string,
event_time string
)PARTITIONED BY(event_month string, step string)
row format delimited fields terminated by '\t';
#这里 (event_month string, step string),如果有一个字段是一级分区,有多个字段的是多级分区
加载(导入)数据
load data local inpath '/home/hadoop/data/order.txt' into table order_mulit_partition PARTITION (event_month='2014-05',step='1');
查询一下
再在hdfs上查看一下
前面所讲的单级分区/多级分区 ==>统称为 静态分区
什么叫静态分区?即导数据时就是把分区字段写全了。
3.动态分区
CREATE TABLE `ruoze_emp_partition`(
`empno` int,
`ename` string,
`job` string,
`mgr` int,
`hiredate` string,
`sal` double,
`comm` double)
partitioned by(`deptno` int)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t';
# 分区的字段是不能出现在表字段里面的,所以deptno是不能出现在create的()里面的。
现在有一个需求,请按照ruoze_emp的这张表的部门编号作为分区字段将ruoze_emp这张表里面的数据写到分区表里面。
按之前的方法是这样:
insert into table ruoze_emp_partition PARTITION(deptno=10)
select empno,ename,job,mgr,hiredate,sal,comm from ruoze_emp where deptno=10;
假设:有1000个deptno,用上面的方法插入的话,那就累死人了。这就是静态分区的弊端,这时可以用动态分区完成,那如何用动态分区去完成?
分区字段里面直接写字段,而不要赋值,另外,还要把分区字段写在select字段的最后面,如果分区字段有两个以上,那select后面的字段也同样要对应上
insert overwrite table ruoze_emp_partition PARTITION(deptno)
select empno,ename,job,mgr,hiredate,sal,comm,deptno from ruoze_emp;
执行后,如果提示上面截图错误提示,是因为默认是严格模式,是无法使用动态赋值的,需要关掉这个值
set hive.exec.dynamic.partition.mode=nonstrict
现在重新执行insert语句
查询一下,select * from ruoze_emp_partition; 已经有数据了。
去hdfs上查看一下,也已经有数据了
所以,如果分区字段的值不固定的话,可以用这个动态分区的方法了。