Hadoop入门学习笔记——七、Hive语法

视频课程地址:https://www.bilibili.com/video/BV1WY4y197g7

课程资料链接:https://pan.baidu.com/s/15KpnWeKpvExpKmOC8xjmtQ?pwd=5ay8

Hadoop入门学习笔记(汇总)

目录

  • 七、Hive语法
    • [7.1. 数据库相关操作](#7.1. 数据库相关操作)
      • [7.1.1. 创建数据库](#7.1.1. 创建数据库)
      • [7.1.2. 选择数据库](#7.1.2. 选择数据库)
      • [7.1.3. 描述数据库详细信息](#7.1.3. 描述数据库详细信息)
      • [7.1.4. 创建数据库并指定其在HDFS系统中的存储位置](#7.1.4. 创建数据库并指定其在HDFS系统中的存储位置)
      • [7.1.5. 删除数据库](#7.1.5. 删除数据库)
      • [7.1.6. 修改数据库存储位置](#7.1.6. 修改数据库存储位置)
      • [7.1.7. 查询当前USE的数据库](#7.1.7. 查询当前USE的数据库)
    • [7.2. 数据表操作](#7.2. 数据表操作)
      • [7.2.1. Hive所支持的数据类型](#7.2.1. Hive所支持的数据类型)
      • [7.2.2. 创建数据表](#7.2.2. 创建数据表)
        • [7.2.2.1. 基础建表语句](#7.2.2.1. 基础建表语句)
        • [7.2.2.2. 基于其他表的结构建表](#7.2.2.2. 基于其他表的结构建表)
        • [7.2.2.3. 基于查询结果建表](#7.2.2.3. 基于查询结果建表)
        • [7.2.2.4. 建表时指定Hive数据分隔符](#7.2.2.4. 建表时指定Hive数据分隔符)
      • [7.2.3. 删除表](#7.2.3. 删除表)
      • [7.2.4. 数据加载和导出](#7.2.4. 数据加载和导出)
        • [7.2.4.1. 数据加载](#7.2.4.1. 数据加载)
        • [7.2.4.2. 数据导出](#7.2.4.2. 数据导出)
      • [7.2.5. 分区表](#7.2.5. 分区表)
      • [7.2.6. 分桶表](#7.2.6. 分桶表)
        • [7.2.6.1. 开启分桶的自动优化(自动匹配Reduce task数量和桶的数量一致)](#7.2.6.1. 开启分桶的自动优化(自动匹配Reduce task数量和桶的数量一致))
        • [7.2.6.2. 创建分桶表](#7.2.6.2. 创建分桶表)
        • [7.2.6.3. 分桶表加载数据](#7.2.6.3. 分桶表加载数据)
      • [7.2.7. 修改表](#7.2.7. 修改表)
        • [7.2.7.1. 表重命名](#7.2.7.1. 表重命名)
        • [7.2.7.2. 修改表的属性](#7.2.7.2. 修改表的属性)
        • [7.2.7.3. 修改表的分区](#7.2.7.3. 修改表的分区)
        • [7.2.7.4. 修改表的列](#7.2.7.4. 修改表的列)
        • [7.2.7.5. 删除表](#7.2.7.5. 删除表)
        • [7.2.7.6. 清空表的数据](#7.2.7.6. 清空表的数据)
      • [7.2.8. 复杂类型操作](#7.2.8. 复杂类型操作)
        • [7.2.8.1. array(数组类型)](#7.2.8.1. array(数组类型))
        • [7.2.8.2. map(Key-Value型)](#7.2.8.2. map(Key-Value型))
        • [7.2.8.3. struct(复合类型)](#7.2.8.3. struct(复合类型))
        • [7.2.8.4. array、map、struct总结](#7.2.8.4. array、map、struct总结)
    • [7.3. 数据查询](#7.3. 数据查询)
      • [7.3.1. 基本查询](#7.3.1. 基本查询)
      • [7.3.2. RLIKE 正则匹配](#7.3.2. RLIKE 正则匹配)
      • [7.3.3. UNION联合](#7.3.3. UNION联合)
      • [7.3.4. Sampling采样](#7.3.4. Sampling采样)
      • [7.3.5. Virtual Columns虚拟列](#7.3.5. Virtual Columns虚拟列)
    • [7.4. 函数](#7.4. 函数)
      • [7.4.1. 数字、集合、转换、日期函数](#7.4.1. 数字、集合、转换、日期函数)
      • [7.4.2. 条件、字符串、脱敏、其它函数](#7.4.2. 条件、字符串、脱敏、其它函数)

七、Hive语法

7.1. 数据库相关操作

7.1.1. 创建数据库

sql 复制代码
CREATE DATABASE [IF NOT EXISTS] db_name [LOCATION 'path'] [COMMENT database_comment];
  • IF NOT EXISTS,如存在同名数据库不执行任何操作,否则执行创建数据库操作
  • [LOCATION],自定义数据库存储位置,如不填写,默认数据库在HDFS的路径为:/user/hive/warehouse
  • [COMMENT database_comment],可选,数据库注释

例如:

sql 复制代码
create database if not exists myhive;

创建一个名字为myhive的数据库,如果该数据已存在,则不再执行创建动作。

7.1.2. 选择数据库

sql 复制代码
USE db_name;
  • 选择数据库后,后续SQL操作基于当前选择的库执行
  • 如不使用use,默认在default库执行

例如:

sql 复制代码
use myhive;

使用myhive数据库;

若想切换回使用default库

sql 复制代码
USE DEFAULT;

7.1.3. 描述数据库详细信息

sql 复制代码
desc database myhive;

可以看到数据库名称、数据库存放路径、所属用户等信息。

可以使用HDFS命令hadoop fs -ls /user/hive/warehouse查看对应的文件;

7.1.4. 创建数据库并指定其在HDFS系统中的存储位置

sql 复制代码
create database myhive2 location '/user/hive/myhive2';

此时可以再次使用desc database myhive2查看myhive2数据库的详细信息,可以看到myhive2数据库的存放路径是按照指定的位置存放的。

7.1.5. 删除数据库

sql 复制代码
DROP DATABASE [IF EXISTS] db_name [CASCADE];
  • [IF EXISTS],可选,如果存在此数据库执行删除,不存在不执行任何操作
  • [CASCADE],可选,级联删除,即数据库内存在表,使用CASCADE可以强制删除数据库

例如:

删除一个空的数据库(无数据、无表)

sql 复制代码
drop  database  myhive;

删除一个非空数据库(有表或有数据)/ 强制删除数据库

sql 复制代码
drop database myhive2 cascade;

7.1.6. 修改数据库存储位置

sql 复制代码
ALTER DATABASE db_name SET LOCATION hdfs_path;

不会在HDFS对数据库所在目录进行改名,只是修改location后,新创建的表在新的路径,旧的不变

7.1.7. 查询当前USE的数据库

sql 复制代码
SELECT current_database();

7.2. 数据表操作

7.2.1. Hive所支持的数据类型

分类 类型 描述 字面量示例
原始类型 BOOLEAN true/false TRUE
TINYINT 1字节的有符号整数 -128~127 1Y
SMALLINT 2个字节的有符号整数,-32768~32767 1S
INT 4个字节的带符号整数 1
BIGINT 8字节带符号整数 1L
FLOAT 4字节单精度浮点数1.0
DOUBLE 8字节双精度浮点数 1.0
DEICIMAL 任意精度的带符号小数 1.0
STRING 字符串,变长 "a",'b'
VARCHAR 变长字符串 "a",'b'
CHAR 固定长度字符串 "a",'b'
BINARY 字节数组
TIMESTAMP 时间戳,毫秒值精度 122327493795
DATE 日期 '2016-03-29'
时间频率间隔
复杂类型 ARRAY 有序的的同类型的集合 array(1,2)
MAP key-value,key必须为原始类型,value可以任意类型 map('a',1,'b',2)
STRUCT 字段集合,类型可以不同 struct('1',1,1.0), named_stract('col1','1','col2',1,'clo3',1.0)
UNION 在有限取值范围内的一个值 create_union(1,'a',63)

7.2.2. 创建数据表

7.2.2.1. 基础建表语句
sql 复制代码
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] tb_name
	(col_name col_type [COMMENT col_comment], ......)
	[COMMENT tb_comment]
	[PARTITIONED BY(col_name col_type, ......)]
	[CLUSTERED BY(col_name, col_name, ......)
	[SORTED BY(col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
	[ROW FORMAT DELIMITED FIELDS TERMINATED BY '']
	[STORED AS SEQUENCEFILE|TEXTFILE|RCFILE]
	[LOCATION 'path']
  • [IF NOT EXISTS],若tb_name不存在则创建;
  • [COMMENT tb_comment],表注释;
  • [EXTERNAL],创建外部表,需与下列属性搭配:
    • [ROW FORMAT DELIMITED FIELDS TERMINATED BY ''],指定数据的分隔符;
    • [LOCATION 'path'],表在HDFS系统中的存放路径;
  • [PARTITIONED BY(col_name col_type, ...)],基于列进行分区存储,col_name为表中没有的列名,col_type为列的类型,支持依据多个列分区,这里的列不与表中的原始的数据列相同;
  • [CLUSTERED BY(col_name, col_name, ...) INTO num_buckets BUCKETS],基于列分桶,col_name为表中已有的列,num_buckets为分桶个数;
  • [STORED AS SEQUENCEFILE|TEXTFILE|RCFILE],存储格式,如果文件数据是纯文本可以用TEXTFILE,如果数据需要压缩可以用SEQUENCEFILE;
  • [LOCATION 'path'],存储位置;

1、内部表和外部表的区别

  • 内部表(CREATE TABLE table_name ...)

    未被external关键字修饰的即是内部表, 即普通表。内部表又称管理表,内部表数据存储的位置由hive.metastore.warehouse.dir参数决定(默认:/user/hive/warehouse),删除内部表会直接删除元数据(metadata)及存储数据,即在MySQL的Hive数据库的TBLS表中的数据和在HDFS系统中的文件都会被删除,因此内部表不适合和其他工具共享数据。

  • 外部表(CREATE EXTERNAL TABLE table_name ...LOCATION...)

    被external关键字修饰的即是外部表, 即关联表。外部表的数据可以放在任何位置,通过LOCATION关键字指定。数据存储的不同也代表了这个表在理念是并不是Hive内部管理的,而是可以随意临时链接到外部数据上的。在删除外部表的时候, 仅删除元数据(表的信息),不会删除数据本身,即仅删除MySQL的Hive数据库的TBLS表中的数据,但HDFS系统中的文件不会被删除。

表类型 创建 存储位置 删除数据 理念
内部表 CREATE TABLE ... Hive管理,默认/user/hive/warehouse - 删除 元数据(表信息) - 删除 数据 Hiv管理表 持久使用
外部表 CREATE EXTERNAL TABLE ... LOCATION ... 随意,LOCATION关键字指定 - 进删除 元数据(表信息) - 保留 数据 临时链接外部数据用

2、使用内部表

使用以下语句建库、建表、插入数据

sql 复制代码
CREATE database myhive;
use myhive;
CREATE table stu(id int, name string);
INSERT INTO stu values(1, '周杰轮'), (2, '林君姐');

插入之后,由于是内部表,可以在HDFS系统中的/user/hive/warehouse/myhive.db/stu文件下看到对应的数据表存储文件

此时,使用hadoop fs -cat命令打开这个文件,查看其里面的内容,即是刚才插入的数据

其他一些创建内部表的方式:

sql 复制代码
-- 基于其它表的结构建表
CREATE TABLE tbl_name LIKE other_tbl;
-- 基于查询结果建表
CREATE TABLE tbl_name AS SELECT ...;

3、使用外部表,关联已有数据
3.1、第一种情况:先有表,后有数据

先在Linux系统中创建一个test_external.txt文件,内容如下(使用\t做为分隔符):

1 itheima

2 itcast

3 hadoop

在创建外部表之前,需要确保外部表所指定的存储位置的目录不存在,在本例中,需要确保HDFS系统中/tmp/test_ext1目录不存在;

然后创建外部表:

sql 复制代码
CREATE external table test_ext1(id int, name string) row format delimited fields terminated by '\t' LOCATION '/tmp/test_ext1';

创建一个外部表,表名为test_ext1,由2个字段id和name构成,该表的数据分隔符为\t,在HDFS系统中的存储位置为/tmp/test_ext1文件夹;

当前因为没有任何数据,所以该文件夹里面没有任何内容,这时,我们通过hadoop fs -puthdfs dfs -put命令将前面在Linux中创建的test_external.txt文件上传到/tmp/test_ext1目录下;

bash 复制代码
hdfs dfs -put test_external.txt /tmp/test_ext1/

上传完成后,在Hive中执行SELECT * FROM test_ext1;语句,便可以看到刚才上传的文件中的数据了;

3.2、第二种情况:先有数据,后有表

先在HDFS中创建一个test_ext2目录

bash 复制代码
hadoop fs -mkdir /tmp/test_ext2

将数据文件上传到test_ext2目录下

bash 复制代码
hadoop fs -put test_external.txt /tmp/test_ext2

然后创建同名(test_ext2)的外部表,并将其存储位置设置为/tmp/test_ext2

sql 复制代码
CREATE external table test_ext2(id int, name string) row format delimited fields terminated by '\t' LOCATION '/tmp/test_ext2';

然后使用SELECT * FROM test_ext2;语句查询数据,发现数据可以被Hive读取到。

3.3、删除外部表

在删除表之前,查看元数据库(MySQL的Hive库)中的TBLS表的数据和HDFS文件系统对应位置的文件夹;

然后执行删表语句drop table test_ext1;,执行成功后,再次查看元数据库(MySQL的Hive库)中的TBLS表的数据和HDFS文件系统对应位置的文件夹;

发现,元数据库中的表信息已被删除,但是HDFS系统中的数据文件仍然存在,未受影响。所以,删除外部表,完全不影响数据本身。

4、内外部表转换

创建一个内部表,创建一个外部表

sql 复制代码
-- 创建内部表t1
CREATE table t1(id int);
-- 创建外部表t2
CREATE external table t2(id int) row format delimited fields terminated by '\t' LOCATION '/tmp/t2';

使用desc formatted t1;语句查看t1表信息,可以看到,该表存储的位置在/user/hive/warehouse文件夹下,且其表类型为MANAGED_TABLE(即管理表,内部表);

使用desc formatted t2;语句查看t2表信息,可以看到,该表存储的位置在/tmp/t2文件夹下,且其表类型为EXTERNAL_TABLE(即外部表);

4.1、内部表转换成外部表

sql 复制代码
ALTER table t1 set TBLPROPERTIES ('EXTERNAL'='TRUE');

将t1表从内部表转换成外部表。

4.2、外部表转换成内部表

sql 复制代码
ALTER table t2 set TBLPROPERTIES ('EXTERNAL'='FALSE');

将t2表从外部表转换成内部表,注意括号里的EXTERNAL和TRUE、FALSE必须大写。

7.2.2.2. 基于其他表的结构建表
sql 复制代码
CREATE TABLE tbl_name LIKE other_tbl;
7.2.2.3. 基于查询结果建表
sql 复制代码
CREATE TABLE tbl_name AS SELECT ...;
7.2.2.4. 建表时指定Hive数据分隔符

在HDFS系统中,通过hadoop fs -cathdfs dfs -cat命令查看Hive数据文件的内容时,在命令行里是看不到数据列的分隔符,这是因为,默认的分隔符是"\001",是一个不可见的ASCII码,键盘打不出来,在有些文本编辑器中,其会显示为SOH,如下所示:

如果我们将Hive数据表文件下载到Linux服务器,然后使用vim工具打开查看,其会显示为^A,如下图所示:

当然,数据分隔符也是可以指定的,在创建表的时候,通过row format delimited fields terminated by可以指定,如将分隔符设置为一个制表符,则建表时可以如下写:

sql 复制代码
create table if not exists stu2(id int ,name string) row format delimited fields terminated by '\t';

7.2.3. 删除表

sql 复制代码
DROP TABLE tbl;

例如:

sql 复制代码
DROP table test;
DROP table myhive.test;

删除test表。

7.2.4. 数据加载和导出

7.2.4.1. 数据加载

1、LOAD语法(从文件向表导入数据)

在Hive客户端中执行以下语句:

sql 复制代码
LOAD DATA [LOCAL] INPATH 'path' [OVERWRITE] INTO TABLE tb_name [PARTITION(partition_key='partition_value')];

[LOCAL],表示要加载的数据文件是否在Linux文件系统中,若在Linux文件系统则需要写上LOCAL,若在HDFS系统则不需要写LOCAL;

'path',表示要加载的文件路径;

[OVERWRITE],表示是否要覆盖表中已有的数据(即表中原有的数据都删除,只保留本次导入的数据);

tb_name,为将数据加载进入的表名。

用法:

先创建一个内部表;

sql 复制代码
CREATE table myhive.test_load(
	dt string comment '时间',
	user_id string comment '用户id',
	search_word string comment '搜索关键词',
	url string comment '网址'
) comment '搜索引擎日志表' row format delimited fields terminated by '\t'

1.1、从Linux系统加载数据到Hive表中

将课程资料中的search_log.txt文件上传到node1服务器的/home/hadoop目录下;

直接从Linux系统中加载数据到test_load表;

sql 复制代码
load data local inpath '/home/hadoop/search_log.txt' into table test_load;

此时,数据就已经加载到了test_load表(加载速度很快);

1.2、从HDFS系统中加载数据到Hive表

将前面的search_log.txt文件上传到HDFS系统/tmp目录下;

bash 复制代码
hdfs dfs -put search_log.txt /tmp/

将HDFS文件系统中的search_log.txt文件加载到test_load表;

sql 复制代码
load data inpath '/tmp/search_log.txt' into table test_load;

此时,数据已导入test_load表中;

可以看到,数据已经变成了2份,第一份是前面从Linux本地导入的,第二份是从HDFS文件系统导入的;

此时,再次查看HDFS系统的/tmp目录,会发现之前上传的search_log.txt文件已经没有了,其实这个导入操作本质上是移动HDFS文件到Hive库表所在的目录。

1.3、演示overwirte属性

再次执行从Linux本地加载数据,但本次带上overwrite属性

sql 复制代码
load data local inpath '/home/hadoop/search_log.txt' overwrite into table test_load;

执行完成后,再次查看test_load表的内容,会发现只剩了文件中的内容,而不像之前一样追加,这里是覆盖的写,该表中原有的数据全部被清空,只保留了本次导入的数据。

2、INSERT SELECT语法(从其他表向表导入数据)

在Hive客户端中执行以下语句:

sql 复制代码
INSERT [OVERWRITE | INTO] TABLE tb_name1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] SELECT select_statement1 FROM from_statement;

将SELECT查询语句的结果插入到其它表中,被SELECT查询的表可以是内部表或外部表。

[OVERWRITE | INTO],表示覆盖或追加数据,覆盖时用OVERWRITE,追加时用INTO;

tb_name1,表示数据导入目标表的表名;

用法:

先创建一个内部表;

sql 复制代码
CREATE table myhive.test_load2(
	dt string comment '时间',
	user_id string comment '用户id',
	search_word string comment '搜索关键词',
	url string comment '网址'
) comment '搜索引擎日志表2' row format delimited fields terminated by '\t';

将test_load表中的数据导入test_load2

sql 复制代码
INSERT INTO table test_load2 select * FROM test_load;

执行上述语句,会发现又被转换成MapReduce任务执行,所以在大规模数据下与LOAD DATA没有区别,但是在小规模数据下,使用LOAD DATA会更快一些。

此时,test_load2表中已经有了数据。

如果再次执行上面的SQL,会发现test_load2表里面的数据会被追加一份。

如果将上面的SQL语句修改为:

sql 复制代码
INSERT OVERWRITE table test_load2 select * FROM test_load;

执行完成后,查看数据,会发现之前的数据被覆盖了,只保留了本次SQL执行的结果。

3、数据导入方式的选择

  • 数据在Linux本地
    • 推荐使用load data local方式加载;
  • 数据在HDFS系统
    • 如果不需要保留源文件:推荐使用load data方式加载;
    • 如果需要保留源文件:推荐使用外部表先关联数据,然后通过insert select方式加载;
  • 数据已经在Hive表中
    • 只能使用insert select方式加载。
7.2.4.2. 数据导出

1、INSERT OVERWRITE方式

在Hive客户端中执行以下语句:

sql 复制代码
insert overwrite [local] directory 'path' [row format delimited fields terminated by ''] select select_statement1 FROM from_statement;

将select语句的结果写入指定的文件中。

[local],表示是否导出到Linux系统本地,若是,则带上该参数,若不是,则不用写;

'path',表示Linux本地或HDFS系统中的路径,若前面有local,这里写的就是Linux系统路径,若没有local,这里写的就是HDFS文件系统路径,这里的path是一个文件夹;

[row format delimited fields terminated by ''],表示指定导出数据时所使用的数据分隔符(与表所使用的数据分隔符无关),默认分隔符为ASCII码\001,不可见。

用法:

1.1、导出数据到本地:

sql 复制代码
INSERT overwrite local directory '/home/hadoop/export1' select * FROM test_load;

将test_load表中的数据导出到Linux系统的/home/hadoop/export1文件夹中。

执行时发现,该语句需要被转换成MapReduce任务执行;

执行完成后,可以在/home/hadoop目录下看到export1文件夹;

进入该文件夹,并查看其内文件的内容

上图可以看到导出的数据,但是由于导出时未指定数据分隔符,所以使用的是默认分隔符,是不可见内容;

将上述导出语句中增加指定分隔符的参数:

sql 复制代码
INSERT overwrite local directory '/home/hadoop/export2' row format delimited fields terminated by '\t' select * FROM test_load;

此时查看Linux本地的/home/hadoop/export2目录及其内容如下,可以看到导出的数据已通过\t进行了分割:

1.2、导出数据到HDFS系统中

sql 复制代码
INSERT overwrite directory '/tmp/export_to_hdfs1' row format delimited fields terminated by '\t' select * FROM test_load;

执行完成后,查看HDFS文件/tmp目录下的内容

2、hive shell方式

在Linux的命令行下执行:

bash 复制代码
./hive -e "select ... from ...;" > 'local_path'
# 或
./hive -f 'sql_file_path' > 'local_path'

"select ... from ...;",表示要执行的SQL语句;

'local_path',表示要导出的Linux文件路径;

'sql_file_path',表示要执行的SQL脚本文件在Linux中的路径;

用法:

2.1、通过SQL语句导出数据

bash 复制代码
# 切换目录
cd /export/server/hive/bin
# 将Hive中的myhive库的test_load表的内容导出到Linux系统/home/hadoop/下的export3.txt文件中
./hive -e "select * from myhive.test_load;" > /home/hadoop/export3.txt
# 查看/home/hadoop/export3.txt的
cat /home/hadoop/export3.txt


2.2、通过SQL文件导出数据

在Linux系统/home/hadoop目录下创建一个export.sql文件,写入如下内容:

sql 复制代码
select * from myhive.test_load;

然后在Linux的命令行中执行如下命令:

bash 复制代码
# 使用hive -f命令,执行export.sql文件中的SQL语句,将其执行结果导出到当前目录下的export4.txt文件中
/export/server/hive/bin/hive -f export.sql > export4.txt
# 查看export4.txt文件内容
cat export4.txt

7.2.5. 分区表

在大数据中,最常用的一种思想就是分治,我们可以把大的文件切割划分成一个个的小的文件,这样每次操作一个小的文件就会很容易了。

在hive当中也是支持这种思想的,就是我们可以把大的数据,按照一定的规则(如每天、每小时等)切分成一个个小的文件。

每一个分区,都是一个文件夹。同时,Hive也支持多个字段作为分区,多分区带有层级关系。

1、创建一个按月进行单分区(按month分区)的学生成绩表,并指定数据分隔符为\t

sql 复制代码
CREATE table myhive.score(
	id STRING COMMENT '学生ID',
	cid STRING COMMENT '课程ID',
	score int COMMENT '课程分数'
) COMMENT '学生成绩表'
partitioned by (month STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

将课程资料中score.txt文件加载到上表中,并指定分区的月份为202005;

sql 复制代码
load data local inpath '/home/hadoop/score.txt' into table myhive.score partition(month='202005');

上面创建的表,相当于有4个列,前3个列从数据文件中获取,最后一个列是当数据插入时进行指定;

sql 复制代码
load data local inpath '/home/hadoop/score.txt' into table myhive.score partition(month='202006');

再加载一次数据,本次指定month为 202006。

然后查看HDFS系统中score表所对应目录的情况;

对Linux本地的score.txt文件修改一些内容,然后再次加载数据

sql 复制代码
load data local inpath '/home/hadoop/score.txt' into table myhive.score partition(month='202007');



2、创建一个按年、月、日,三个层次的多分区学生成绩表,并指定数据分隔符为\t

sql 复制代码
CREATE table myhive.score2(
	id STRING COMMENT '学生ID',
	cid STRING COMMENT '课程ID',
	score int COMMENT '课程分数'
) COMMENT '学生成绩表2'
partitioned by (year STRING, month STRING, day STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

这个表实际有6个字段,其中前3个是数据列,后3个是在数据插入时指定的分区列

将Linux系统中score.txt的数据加载到上面的多分区表中

sql 复制代码
load data local inpath '/home/hadoop/score.txt' into table myhive.score2 partition(year="2022", month='01', day="10");

此时,score2表中的数据为,可以看到id,cid和score的数据来自score.txt文件的内容,而year,month,day三个字段的数据来自导入语句指定;

然后再查看HDFS系统中的目录结构

再导入几次数据

sql 复制代码
load data local inpath '/home/hadoop/score.txt' into table myhive.score2 partition(year="2022", month='01', day="11");
load data local inpath '/home/hadoop/score.txt' into table myhive.score2 partition(year="2023", month='01', day="11");
load data local inpath '/home/hadoop/score.txt' into table myhive.score2 partition(year="2022", month='02', day="11");

此时,再次查看HDFS系统中score2目录下的目录结构

3、分区表在创建时指定的分区字段,在插入数据时必须都要传入,否则Hive会报错。
4、分区表查询时,如果以分区列做为where条件,会极大的提高查询效率,因为只需要读取对应文件夹下的数据即可。

7.2.6. 分桶表

分桶和分区一样,也是一种通过改变表的存储模式,从而完成对表优化的一种调优方式

但和分区不同,分区是将表拆分到不同的子文件夹中进行存储,而分桶是将表拆分到固定数量的不同文件中进行存储。

7.2.6.1. 开启分桶的自动优化(自动匹配Reduce task数量和桶的数量一致)
sql 复制代码
set hive.enforce.bucketing = TRUE;
7.2.6.2. 创建分桶表
sql 复制代码
CREATE table myhive.course(c_id string, c_name string, t_id string) clustered by (c_id)
INTO 3 buckets row format delimited fields terminated by '\t';

创建一个course表,根据表中的c_id字段分三个桶;

7.2.6.3. 分桶表加载数据

由于桶表的数据加载通过load data无法执行,只能通过insert select方式加载。

1、创建一个临时表(外部表或内部表均可),通过load data把数据加载到临时表;

sql 复制代码
-- 创建临时中转表(需要注意,中转表的分隔符需要与分桶表保持一致)
CREATE table myhive.course_temp(c_id string, c_name string, t_id string) row format delimited fields terminated by '\t';
-- 将数据加载到中转表
load data local inpath '/home/hadoop/course.txt' into table myhive.course_temp;

2、从临时表通过insert select方式将数据加载到分桶表;

sql 复制代码
INSERT overwrite table myhive.course select * FROM myhive.course_temp cluster by(c_id);

这里需要注意,在向分桶表插入数据时,需要使用cluster by标明分桶依赖字段。注意,这里是cluster,而不是建表时缩写的clustered!

此时,我们可以查看HDFS系统中的文件情况hadoop fs -ls /user/hive/warehouse/myhive.db/course

会发现,course表的数据被放在了三个文件中,这里是因为最开始创建分桶表时,指定的分桶数量为3,如果指定其他数量的分桶数,那就会生成对应的文件个数。

3、为什么不可以用load data,必须用insert select插入数据

如果没有分桶设置,插入(加载)数据只是简单的将数据放入到:

  • 表的数据存储文件夹中(没有分区);
  • 表指定分区的文件夹中(带有分区)。

一旦有了分桶设置,比如分桶数量为3,那么,表内文件或分区内数据文件的数量就限定为3。当数据插入的时候,需要一分为3,进入三个桶文件内。

数据的三份划分基于分桶列的值进行hash取模来决定,由于load data不会触发MapReduce,也就是没有计算过程(无法执行Hash算法),只是简单的移动数据而已,所以无法用于分桶表数据插入。

7.2.7. 修改表

7.2.7.1. 表重命名

语法:

sql 复制代码
alter  table  old_table_name  rename  to  new_table_name;

old_table_name,当前的表名;

new_table_name,新的表名。

例如:

sql 复制代码
--将表score2重命名成score3
ALTER table score2 rename to score3;
7.2.7.2. 修改表的属性

语法:

sql 复制代码
ALTER TABLE table_name SET TBLPROPERTIES table_properties;
table_properties:
  : (property_name = property_value, property_name = property_value, ... )

例如:

sql 复制代码
-- 将score3修改为外部表
ALTER table score3 set TBLPROPERTIES("EXTERNAL"="TRUE");
-- 将score3表的注释修改为this is table comment
ALTER table score3 set TBLPROPERTIES("comment"="this is table comment");

其余属性可参见:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-listTableProperties

7.2.7.3. 修改表的分区

1、添加分区

语法:

sql 复制代码
ALTER TABLE tablename  ADD PARTITION (month='201101');

例如:

sql 复制代码
-- 给score3表添加一个year为2019,month为10,day为01的分区
ALTER table score3 add partition(year='2019', month='10', day='01');

分区添加完成之后,因为新分区内还没有数据,所以在Hive中是看不到的,但是可以在HDFS中看到对应的目录;

可以通过手动添加数据文件或者加载数据的方式导入数据;

例如,将另一个分区的数据文件复制一份过来hadoop fs -cp /user/hive/warehouse/myhive.db/score3/year=2022/month=01/day=10/score.txt /user/hive/warehouse/myhive.db/score3/year=2019/month=10/day=01/,这时,在DBeaver中就可以看到新分区中出现了数据

2、修改分区值(一般不要修改)

语法:

sql 复制代码
ALTER TABLE tablename PARTITION (month='202005') RENAME TO PARTITION (month='201105');

例如:

sql 复制代码
-- 将score3表year为2019,month为10,day为01的分区修改为year为2019,month为10,day为07
ALTER table score3 partition(year='2019', month='10', day='01') rename to partition(year='2019', month='10', day='07');

这时可以查看DBeaver中的数据,发现数据已经被修改了;

同时,查看HDFS系统中的目录结构,发现文件目录并没有修改。这时因为,修改分区值本质上是修改元数据,而HDFS系统中的文件夹不会被重命名(默认元数据中的分区值和HDFS系统中的文件夹名字是一样的,但是也可以不同)。

此时,可以连接元数据库(node1服务器上的MySQL数据库),进入hive库,查看PARTITIONS表的内容,会发现分区名字已经变为了year=2019/month=10/day=07,其SD_ID为14,其TBL_ID为5,对应的字典为score3(表名);

然后再查看SDS表中的数据,会发现SD_ID为14的数据,其对应的LOCATION的值为hdfs://node1:8020/user/hive/warehouse/myhive.db/score3/year=2019/month=10/day=01,通过这两个表实现了分区和HDFS系统中文件夹的对应,同时,也可以看到分区值已经变更了,但是HDFS中的物理存储路径没有变化。

当然,也可以先手动修改HDFS系统中对应路径的文件夹名,然后再来SDS表中修改LOCATION的值到新的路径,就可以实现分区值和HDFS路径一样了。

3、删除分区

语法:

sql 复制代码
ALTER TABLE tablename DROP PARTITION (month='201105');

例如:

sql 复制代码
-- 删除score3表中year为2019,month为10,day为07的分区
ALTER table score3 drop partition(year='2019', month='10', day='07');

删除分区后,Hive表中对应分区的数据也会被删除,但是HDFS系统中的相关文件夹和数据文件不会被删除。

这时因为删除分区只是删除了元数据,数据本身还在。

7.2.7.4. 修改表的列

1、添加列

语法:

sql 复制代码
ALTER TABLE table_name ADD COLUMNS (col_name col_type, col_name col_type, ...);

例如:

sql 复制代码
-- 给score3增加v1,v2两列,分别是int型和string型
ALTER table score3 add columns (v1 int, v2 string);

可以看到执行后score3表增加了两个列

2、修改列名

语法:

sql 复制代码
ALTER TABLE table_name CHANGE old_col_name new_col_name old_col_type;

例如:

sql 复制代码
-- 将score3表中的v1列改为v1new列,int型(尽量不要修改类型,有可能会报错)
ALTER table score3 change v1 v1new int;

此时,查看score3表的结构,发现v1列已经改名为v1new列。

7.2.7.5. 删除表

语法:

sql 复制代码
DROP TABLE tablename;

例如:

sql 复制代码
-- 删除myhive库下的score3表
DROP table myhive.score3;
7.2.7.6. 清空表的数据

语法:

sql 复制代码
TRUNCATE TABLE tablename;

例如:

sql 复制代码
-- 清空course表内的数据
TRUNCATE table course;

尝试清空外部表:

sql 复制代码
-- 将test_load2表改成外部表
ALTER table test_load2 set TBLPROPERTIES("EXTERNAL"="TRUE");
-- 清空test_load2表内的数据
TRUNCATE table test_load2;

此时,会发现系统会报错。所以外部表无法被Hive清空。

SQL 错误 [10146] [42000]: Error while compiling statement: FAILED: SemanticException [Error 10146]: Cannot truncate non-managed table test_load2.

7.2.8. 复杂类型操作

Hive支持的数据类型很多,除了基本的:int、string、varchar、timestamp等,还有一些复杂的数据类型,如:array(数组类型)、map(映射类型)、struct(结构类型)等。

7.2.8.1. array(数组类型)

Hive中的array类型与Java中的List非常相似,在定义Hive表结构是指定字段为array类型,同时,还需指定array内的元素的类型。

创建数据表:

sql 复制代码
CREATE table myhive.test_array(name string, work_locations array<string>)
row format delimited fields terminated by '\t'
COLLECTION ITEMS TERMINATED BY ',';

array<string>,表示work_locations字段的类型为array数组类型,数据内的元素为string型;

row format delimited fields terminated by '\t', 表示数据分隔符是制表符\t;

COLLECTION ITEMS TERMINATED BY ',', 表示集合(array)内元素的分隔符是英文逗号(,);

加载数据:

将课程资料中的data_for_array_type.txt放到Linux系统/home/hadoop目录下,然后执行以下SQL:

sql 复制代码
load data local inpath '/home/hadoop/data_for_array_type.txt' into table test_array;

加载完成后,可以在Hive表中看到对应的数据

查询数据:

sql 复制代码
-- 查询所有数据
SELECT * from test_array;
-- 查询每个人工作的第一个城市
SELECT name, work_locations[0] from test_array;
sql 复制代码
-- 查询array类型中的元素个数
SELECT name, SIZE(work_locations) from test_array;
sql 复制代码
-- 找出在tianjin工作过的人
 SELECT * FROM test_array WHERE ARRAY_CONTAINS(work_locations, 'tianjin');
7.2.8.2. map(Key-Value型)

map类型其实就是简单的指代:Key-Value型数据格式。 有如下数据文件,其中members字段是key-value型数据。字段与字段分隔符: ",";需要map字段之间的分隔符:"#";map内部k-v分隔符:":"。

id,name,members,age

1,zhangsan,father:xiaoming#mother:xiaohuang#brother:xiaoxu,28

2,lisi,father:mayun#mother:huangyi#brother:guanyu,22

3,wangwu,father:wangjianlin#mother:ruhua#sister:jingtian,29

4,mayun,father:mayongzhen#mother:angelababy,26

创建数据表

sql 复制代码
CREATE table myhive.test_map(
	id int,
	name string,
	members map<string, string>,
	age int
) row format delimited fields terminated by ','
COLLECTION ITEMS TERMINATED BY '#'
MAP KEYS TERMINATED BY ':';

map<string, string>,指定members字段的类型为键为string型,值为string型的键值对;

row format delimited fields terminated by ',',指定数据列之间的分隔符为英文逗号(,);

COLLECTION ITEMS TERMINATED BY '#',指定每个键值对之间的分隔符为#号;

MAP KEYS TERMINATED BY ':',指定MAP键和值之间的分隔符为英文冒号(:)。

加载数据

将课程资料中的data_for_map_type.txt放到Linux系统/home/hadoop目录下,然后执行以下SQL:

sql 复制代码
load data local inpath '/home/hadoop/data_for_map_type.txt' into table test_map;

加载前,可以通过cat data_for_map_type.txt命令查看文件内容如下:

加载完成后,打开test_map表查看数据:

数据查询

sql 复制代码
-- 查看每行数据members字段中的father和monther元素
SELECT id, name, members['father'], members['mother'] FROM myhive.test_map;
sql 复制代码
-- 取出map的全部key,map_keys函数返回的类型是array
SELECT map_keys(members) from myhive.test_map;
sql 复制代码
-- 取出map的全部value,map_values函数返回的类型是array
SELECT map_values(members) from myhive.test_map;
sql 复制代码
-- 查看map的个数,size函数
SELECT id, name, members, SIZE(members), age from myhive.test_map;
sql 复制代码
-- 查看指定的数据是否包含在map中,array_contains函数,查看谁有sister这个key
SELECT * from myhive.test_map WHERE ARRAY_CONTAINS(map_keys(members), "sister") ;
-- 查看指定的数据是否包含在map中,array_contains函数,查看谁有"王林"这个value
SELECT * from myhive.test_map WHERE ARRAY_CONTAINS(map_values(members), "王林") ;
7.2.8.3. struct(复合类型)

struct类型是一个复合类型,可以在一个列中存入多个子列,每个子列允许设置类型和名称。有如下数据文件,字段之间#分割,struct之间冒号分割。

1#周杰轮:11

2#林均杰:16

3#刘德滑:21

4#张学油:26

5#蔡依临:23

创建数据表

sql 复制代码
CREATE table myhive.test_struct(
	id string,
	info struct<name:string, age:int>
) row format delimited fields terminated by '#'
COLLECTION ITEMS TERMINATED BY ':';

info struct<name:string, age:int>,指定info列为stuct型,其内部又分为两个子列,分别是name(string型)和age(int型);

row format delimited fields terminated by '#',指定表的每一列的数据分隔符为#号;

COLLECTION ITEMS TERMINATED BY ':',指定struct型内,每个子列的数据分隔符为英文冒号(:)。

加载数据

将课程资料中的data_for_struct_type.txt放到Linux系统/home/hadoop目录下,然后执行以下SQL:

sql 复制代码
load data local inpath '/home/hadoop/data_for_struct_type.txt' into table test_struct;

加载前,可以通过vim data_for_map_type.txt命令查看文件内容如下:

加载完成后,打开test_struct表查看数据:

数据查询

sql 复制代码
-- 查询id和对应info中的name的值
SELECT id, info.name from myhive.test_struct;
7.2.8.4. array、map、struct总结
类型 定义 示例 内含元素类型 元素个数 取元素 可用函数
array array<类型> 如定义为:array<int> 数据为:1,2,3,4,5 单值,类型取决于定义 动态,不限制 array[下标索引] 索引从0开始 size()统计元素个数 array_contains()判断是否包含指定数据
map map<key类型, value类型> 如定义为:map<string, int> 数据为:{'a':1, 'b':2, 'c':3} 键值对,K-V,K和V类型取决于定义 动态,不限制 map[key]取出对应key的value size()统计元素个数 map_keys()取出全部key,返回array map_values()取出全部value,返回array array_contains()判断是否包含指定数据,须与map_keys()或map_values()配合使用,在where子句中做搜索条件
struct struct<子列名1 子列类型1, 子列名2 子列类型2, ...> 如定义为:struct<c1 string, c2 int, c3 date> 数据为:'a', 1, '2023-01-01' 单值,类型取决于定义 固定,取决于定义的子列数量 struct.子列名 通过子列名取出子列的值 暂无

7.3. 数据查询

准备数据

将课程资料中的itheima_orders.txt和itheima_users.txt放到Linux系统/home/hadoop目录下,然后执行以下SQL:

sql 复制代码
-- 创建新的库
CREATE database itheima;
-- 选择itheima库
use itheima;
-- 创建订单表
CREATE TABLE itheima.orders (
    orderId bigint COMMENT '订单id',
    orderNo string COMMENT '订单编号',
    shopId bigint COMMENT '门店id',
    userId bigint COMMENT '用户id',
    orderStatus tinyint COMMENT '订单状态 -3:用户拒收 -2:未付款的订单 -1:用户取消 0:待发货 1:配送中 2:用户确认收货',
    goodsMoney double COMMENT '商品金额',
    deliverMoney double COMMENT '运费',
    totalMoney double COMMENT '订单金额(包括运费)',
    realTotalMoney double COMMENT '实际订单金额(折扣后金额)',
    payType tinyint COMMENT '支付方式,0:未知;1:支付宝,2:微信;3、现金;4、其他',
    isPay tinyint COMMENT '是否支付 0:未支付 1:已支付',
    userName string COMMENT '收件人姓名',
    userAddress string COMMENT '收件人地址',
    userPhone string COMMENT '收件人电话',
    createTime timestamp COMMENT '下单时间',
    payTime timestamp COMMENT '支付时间',
    totalPayFee int COMMENT '总支付金额'
) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
-- 加载数据到orders表中
load data local inpath '/home/hadoop/itheima_orders.txt' into table itheima.orders;
-- 创建用户表
CREATE TABLE itheima.users (
    userId int,
    loginName string,
    loginSecret int,
    loginPwd string,
    userSex tinyint,
    userName string,
    trueName string,
    brithday date,
    userPhoto string,
    userQQ string,
    userPhone string,
    userScore int,
    userTotalScore int,
    userFrom tinyint,
    userMoney double,
    lockMoney double,
    createTime timestamp,
    payPwd string,
    rechargeMoney double
) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
-- 加载数据到users表中
load data local inpath '/home/hadoop/itheima_users.txt' into table itheima.users;

7.3.1. 基本查询

Hive中使用基本查询SELECT、WHERE、GROUP BY、聚合函数、HAVING、JOIN和普通的SQL语句没有区别。

查询语句的基本语法:

sql 复制代码
SELECT [ALL | DISTINCT]select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BYcol_list]
[HAVING where_condition]
[ORDER BYcol_list]
[CLUSTER BYcol_list
  | [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number]

整体上和普通SQL差不多,部分有区别,如:CLUSTER BY、DISTRIBUTE BY、SORT BY等。

SELECT基础查询

sql 复制代码
-- 查询全表数据
SELECT * FROM itheima.orders;

-- 查询单列信息
SELECT orderid, userid, totalmoney FROM itheima.orders;

-- 查询表中总共有多少条数据(会转成MapReduce任务执行)
SELECT count(*) FROM itheima.orders;

-- 查询表中广东省的订单
SELECT * FROM itheima.orders o WHERE o.useraddress LIKE '广东%';

-- 找出广东省单笔金额最大的订单(会转成MapReduce任务执行)
SELECT * FROM itheima.orders o WHERE o.useraddress LIKE '广东%' ORDER BY o.totalmoney DESC LIMIT 1;

分组、聚合查询

sql 复制代码
-- 统计未支付、已支付各自的人数(会转成MapReduce任务执行)
SELECT ispay, COUNT(*) FROM itheima.orders GROUP BY ispay;

-- 在已付款的订单中,统计每个用户最高额度一笔消费金额(会转成MapReduce任务执行)
SELECT userid, MAX(totalmoney) FROM itheima.orders WHERE ispay = 1 GROUP BY userid;

-- 统计每个用户的平均订单消费额(会转成MapReduce任务执行)
SELECT userid, AVG(totalmoney) FROM itheima.orders GROUP BY userid; 

-- 统计每个用户的平均订单消费额,并过滤大于10000的数据(会转成MapReduce任务执行)
SELECT userid, AVG(totalmoney) as avg_totalmoney FROM itheima.orders GROUP BY userid HAVING avg_totalmoney > 10000; 

JOIN查询

sql 复制代码
-- JOIN(内关联)订单表和用户表,找出用户名
SELECT o.orderid, o.userid, u.username FROM orders o JOIN users u ON u.userid = o.userid;

-- 左外关联,订单表和用户表,找出用户名
SELECT o.orderid, o.userid, u.username FROM orders o LEFT JOIN users u ON u.userid = o.userid;

7.3.2. RLIKE 正则匹配

Hive中提供RLIKE关键字,可以供用户使用正则和数据进行匹配。

RLIKE匹配

sql 复制代码
-- 查找广东省的数据
SELECT * FROM itheima.orders o WHERE o.useraddress RLIKE '.*广东.*';

-- 查找用户地址是:XX省 XX市 XX区的数据
SELECT * FROM itheima.orders o WHERE o.useraddress RLIKE '..省 ..市 ..区';

-- 查找用户姓为张、王、邓的数据
SELECT * FROM itheima.orders o WHERE o.username RLIKE '[张王邓].+';
SELECT * FROM itheima.orders o WHERE o.username RLIKE '[张王邓]\\S+';

-- 查找手机号复合:188****0***规则的订单
SELECT * FROM itheima.orders o WHERE o.userphone RLIKE '188.{4}0.{3}';
SELECT * FROM itheima.orders o WHERE o.userphone RLIKE '188\\S{4}0[0-9]{3}';

7.3.3. UNION联合

7.3.4. Sampling采样

7.3.5. Virtual Columns虚拟列

7.4. 函数

7.4.1. 数字、集合、转换、日期函数

7.4.2. 条件、字符串、脱敏、其它函数

相关推荐
开MINI的工科男1 小时前
【笔记】自动驾驶预测与决策规划_Part3_路径与轨迹规划
人工智能·笔记·自动驾驶·预测与决策
wang_book1 小时前
Gitlab学习(007 gitlab项目操作)
java·运维·git·学习·spring·gitlab
weixin_455446172 小时前
Python学习的主要知识框架
开发语言·python·学习
isNotNullX3 小时前
一文解读OLAP的工具和应用软件
大数据·数据库·etl
Ylucius4 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
LvManBa5 小时前
Vue学习记录之六(组件实战及BEM框架了解)
vue.js·学习·rust
不是笨小孩i5 小时前
Git常用指令
大数据·git·elasticsearch
LvManBa5 小时前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
洛寒瑜5 小时前
【读书笔记-《30天自制操作系统》-23】Day24
开发语言·汇编·笔记·操作系统·应用程序