Hadoop07---Hive基础

HIVE

一 hive的启动与连接

使用hive的前提:安装好sql、hadoop、hdfs、yarn

1.启动hive

  • 初始化:

    • 只执行一次,执行过后,后面再次启动时不需要执行

    • 在bin目录下执行:

      schematool -initSchema -dbType mysql

  • 开启元数据服务

    • 前台启动:

      hive --service metastore

    • 后台启动:

      hive --service metastore &

  • 直接启动:hive

  • 远程连接启动:

    • 先开启hiveserver2服务:hiveserver2

    • 使用JDBC连接:jdbc:hive2://linux01:10000

    • beeline端:

      • 直接输入beeline进入beeline客户端

      • 连接hive2服务端口(等待hiveserver2加载出4个Hive Session ID)

        !connect jdbc:hive2://linux01:10000

        输入用户名:root

        输入密码:默认没有,直接回车

      • beeline中可以操作hdfs

    • IDEA端:

      • 新建maven项目
      • 添加依赖:
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-jdbc</artifactId>
      <version>1.2.1</version>
      
      • 新建—>Data Source—>Apache Hive

      • 添加连接信息

        image-20201129140916861

  • 启动成功标志:

    • jps进程(3个RunJar):
      • 元数据服务一个RunJar
      • hiveserver2一个RunJar
      • hive2的进程一个RunJar

    [外链图片转存中…(img-IuaL3vn2-1607216353289)]

    • 端口:
      • SQL:3306
      • 元数据服务:9083
      • hiveserver2:10000

2.远程连接

  • hive通过设置hive-site.xml将元数据存储到mysql中,连接了mysql与hdfs
    • 元数据的数据库信息存储在mysql—>hive表—>DBS表中
    • 表信息存储在mysql—>hive表—>TBLS表中
  • 在hive中,可以直接方位hdfs和linux文件系统
    • 访问hdfs:dfs -help
    • 访问linux:! help

3.linux操作hive(-e和-f)

  • “-e”不进入hive的交互窗口执行sql语句

    [root@doit01hive]$ bin/hive -e “select id from student;”

  • “-f”执行脚本中sql语句

    • 在/opt/module/datas目录下创建hivef.sql文件

      [root@doit01datas]$ touch hivef.sql

    • 文件中写入正确的sql语句

      select *from student;

    • 执行文件中的sql语句

      [root@doit01hive]$ bin/hive -f /opt/module/datas/hivef.sql

    • 执行文件中的sql语句并将结果写入文件中

      [root@doit01hive]$ bin/hive -f /opt/module/datas/hivef.sql > /opt/module/datas/hive_result.txt

二 数据类型

1.基本数据类型

Hive数据类型Java数据类型长度例子
TINYINTbyte1byte有符号整数20
SMALLINTshort2byte有符号整数20
INTint4byte有符号整数20
BIGINTlong8byte有符号整数20
BOOLEANboolean布尔类型,true或者falseTRUE FALSE
FLOATfloat单精度浮点数3.14159
DOUBLEdouble双精度浮点数3.14159
STRINGstring字符系列。可以指定字符集。可以使用单引号或者双引号。‘now is the time’ “for all good men”
TIMESTAMP时间类型
BINARY字节数组

2.集合数据类型

数据类型描述语法示例
STRUCT(结构体)对象和c语言中的struct类似,都可以通过“点”符号访问元素内容。例如,如果某个列的数据类型是STRUCT{first STRING, last STRING},那么第1个元素可以通过字段.first来引用。类似于java中的pojostruct()
MAP 映射MAP是一组键-值对元组集合,使用数组表示法可以访问数据。例如,如果某个列的数据类型是MAP,其中键->值对是’first’->’John’和’last’->’Doe’,那么可以通过字段名[‘last’]获取最后一个元素map()
ARRAY 数组数组是一组具有相同类型和名称的变量的集合。这些变量称为数组的元素,每个数组元素都有一个编号,编号从零开始。例如,数组值为[‘John’, ‘Doe’],那么第2个元素可以通过数组名[1]进行引用。Array()
  • Json数据导入

    • 使用函数:json_tuple ,输入json行字符串,需要的字段的key(需要加引号)

      create table test_json 
      as select json_tuple(str,'movie','rate','timeStamp','uid')  --输入key,以获取值
      as (movie,rate,timeStamp,uid)  --上面要引号,这里不用
      from test_movie2;
      
  • 集合数据类型使用演示:

    准备数据:
    benben,fengjie_furong,xiaoben:18_daben:19,hui long guan_beijing
    yangyang,caicai_susu,xiaoyang:18_xiaoxiao yang:19,chao yang_beijing
    
    建表:
    create table test_jihe (
        name string,
        friends array<string>,
        children map<string,int>,
        addr struct<street:string,city:string>) 
    row format delimited fields terminated by ','	--设置字段分隔符
    collection items terminated by '_' 			--设置集合(array,map)元素的分隔符(struct适用)
    map keys terminated by ':' 					--设置map键值对的分隔符
    lines terminated by '\n';					--设置换行的分隔符(默认\n,可以不写)
    导入数据:
    load data local inpath '/root/anli/jihe/jihe.txt' into table test_jihe;
    

    [外链图片转存中…(img-BjPiLTnQ-1607216353295)]

  • 集合数据常用方法:

    -- 取值:
    array[index]
    map['key']
    struct.属性		e.g	addr.city
    
    -- 获取长度:
    size(arr)
    
    -- 获取map集合中所有的key:
    map_keys(map)
    select map_keys(children) from test_jihe;
    +-------------------------------+
    |              _c0              |
    +-------------------------------+
    | ["xiaoben","daben"]           |
    | ["xiaoyang","xiaoxiao yang"]  |
    +-------------------------------+
    
    -- 获取map集合的所有value:
    map_values(map)
    select map_values(children) from test_jihe;
    +----------+
    |   _c0    |
    +----------+
    | [18,19]  |
    | [18,19]  |
    +----------+
    

三 Hive基础操作

1.DDL语言

1.1 建表语句
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name 
[(col_name data_type [COMMENT col_comment], ...)] 
[COMMENT table_comment] 
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] 分区
[CLUSTERED BY (col_name, col_name, ...) 分桶
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] 
[ROW FORMAT row_format]   row format delimited fields terminated by “分隔符”
[STORED AS file_format]
[LOCATION hdfs_path]


create [external] table [if not exists] table_name 
--创建    [外部(删除表不会删除数据)]  表格 [如果不存在] 表名
[(col_name data_type [comment col_comment], ...)]
--[(列名   数据类型    [标注    列名标注] , ...)]
[comment table_comment]
--[标注   表标注]
[partitioned by (col_name data_type [comment col_comment], ...)]
--[分区      通过 (列名     数据类型    [标注    列标注], ...)]
[clustered by (col_name,col_name, ...)]
--[分桶    通过 (列名  ,  列名  ,  ...)]
[sorted by (col_name [ASC|DESC], ...)] into num_buckets buckets]
--[分类 通过 (列名     [正序|倒序], ...)] 在..中  数字桶    桶 ]
[row format row_format]    row format delimited fields terminated by “分隔符”
--[行 格式   行格式     ]     行   格式    分割      字段     限制     为 
[stored as file_format]
--[存储 作为 文件格式]
[location hdfs_path]
--[地址    路径]
1.2 数据库操作
  • 查询数据库
--显示数据库
show databases;

--过滤显示查询的数据库
show databases like 'db_hive*';
OK
db_hive
db_hive_1

--显示数据库信息
desc database db_hive;
OK
db_hive		hdfs:/doit01:9000/user/hive/warehouse/db_hive.db

--显示数据库详细信息
desc database extended db_hive;
OK
db_hive		hdfs:/doit01:9000/user/hive/warehouse/db_hive.db	

--切换当前数据库
use db_hive;
  • 修改数据库
--使用ALTER DATABASE命令为某个数据库的DBPROPERTIES设置键-值对属性值,来描述这个数据库的属性信息
alter database db_hive set dbproperties('createtime'='20170830');
alter database db_name set dbproperties(''='',''='') ;

--在hive中查看修改结果
hive> desc database extended db_hive;
db_name comment location        owner_name      owner_type      parameters
db_hive         hdfs:/doit01:8020/user/hive/warehouse/db_hive.db   root USER    {createtime=20170830}
  • 删除数据库
--删除空数据库
hive>drop database db_hive2;

--如果数据库不为空,可以采用cascade命令,强制删除
hive> drop database db_hive;
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. InvalidOperationException(message:Database db_hive is not empty. One or more tables exist.)
hive> drop database db_hive cascade;
1.3 表格操作
--查看表格详细信息
desc  formatted  tb_name ;

--重命名表
ALTER TABLE table_name RENAME TO new_table_name;

--更新列(修改列名)
ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]

--增加和替换列(ADD的字段位置在所有列后面(partition列前),REPLACE则是表示替换表中所有字段)
ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...) 

--查询表结构
desc table_name;

2.数据导入

2.1 建表时导入文件

建表的时候指定location—结构化数据的位置文件夹

create external table test01 (id String,name string,age int) row format delimited fields terminated by "," location '/anli/log1';
--注意:location后面的地址是hdfs的地址,地址具体到文件夹,不到文件!

+------------+--------------+-------------+
| test01.id  | test01.name  | test01.age  |
+------------+--------------+-------------+
| uid001     | zss          | 23          |
| uid002     | lss          | 13          |
| uid003     | ww           | 22          |
| uid004     | zl           | 34          |
| uid005     | tq           | 43          |
| uid006     | wb           | 55          |
| uid007     | sj           | 98          |
+------------+--------------+-------------+
2.2 移动文件到指定目录

可以将结构化数据直接put到表目录中,或者mv到指定的目录

移动时注意分隔符和数据类型要相符

dfs -put /root/deyun.log /anli/log1;
--使用hdfs语句上传本地文件
dfs -cp /anli/log1/tp_imp /anli/log1/tp_imp2
--复制文件

+------------+--------------+-------------+
| test01.id  | test01.name  | test01.age  |
+------------+--------------+-------------+
| 1          | guodegang    | 50          |
| 2          | yuqian       | 51          |
| 3          | yueyunpeng   | 33          |
| 4          | sunyue       | 40          |
| 5          | zhanghelun   | 35          |
| uid001     | zss          | 23          |
| uid002     | lss          | 13          |
| uid003     | ww           | 22          |
| uid004     | zl           | 34          |
| uid005     | tq           | 43          |
| uid006     | wb           | 55          |
| uid007     | sj           | 98          |
| uid001     | zss          | 23          |
| uid002     | lss          | 13          |
| uid003     | ww           | 22          |
| uid004     | zl           | 34          |
| uid005     | tq           | 43          |
| uid006     | wb           | 55          |
| uid007     | sj           | 98          |
+------------+--------------+-------------+
2.3 load载入
  • 追加数据:

    - load data local  inpath "/data/user3.csv" into table tb_user ;	
    --底层就是put
    
    - load data  inpath "/user5.csv" into table tb_user ;			
    --底层move(原文件会没)
    
  • 重新数据:加上overwrite

        load data  inpath "/user3.csv" overwrite into table tb_user ;	--底层move
    
2.4 insert数据
  1. 直接insert数据,不建议使用,会产生大量小文件

    insert into tb_user values(1,‘fjj’),(2,‘bgg’) ; – 生成小文件
    insert into tb_user values(1,‘fjj’),(2,‘bgg’) ; – 生成小文件

  2. 将查询结果直接加载到表中

insert into test02  select id,name from test01;

直接向表中load长度不同的数据,全部为null

向表中insert类型相同,或者可转的数据,可以正常加载;类型不同,为null

  1. 将查询结果直接添加到新表中
create table test04 as select id,age from test01;
2.5 import导入

使用import的应用场合比价单一,只有使用export导出的数据才可以用import进行导入

export table test01 to '/anli/log2/test01';			--数据导出

import table test05 from '/anli/log2/test01';		--数据导入

3.数据导出

  • 使用export导出数据

  • 确定hdfs中的存储目录,直接使用get下载数据

  • 使用sqoop dataX 数据迁移工具

  • 使用insert导出

    insert overwrite local directory '/user_data/' select * from tb_user;   	
    -- 将查询的结构数据保存在本地的目录中
    
    insert overwrite  directory '/user_data/' select * from tb_user;		
    -- 将查询的结构数据保存在HDFS目录中
    

4.分区表

分区表:将表的数据以查询维度为依据分文件夹管理 , 当根据这个维度查询的时候减少数据的检索范围

4.1 静态分区

文件中存储的是指定规则的数据,源文件就是依据指定的规则划分好的文件,直接存放到指定的分区目录中

比如:a.log中存储的就是20201130的数据,直接创建一个分区叫20201130,将数据直接load到目录下

实施流程(创建一个三级分区的静态分区表):

  • 准备数据
20201128.log
1,url1,20201128
2,url2,20201128
3,url3,20201128
4,url4,20201128
5,url5,20201128
6,url6,20201128
7,url7,20201128
20201129.log
1,url1,20201129
2,url2,20201129
3,url3,20201129
4,url4,20201129
5,url5,20201129
6,url6,20201129
7,url7,20201129
20201130.log
1,url1,20201130
2,url2,20201130
3,url3,20201130
4,url4,20201130
5,url5,20201130
6,url6,20201130
7,url7,20201130

20191212.log
1,url1,20191212
2,url2,20191212
3,url3,20191212
4,url4,20191212
5,url5,20191212
6,url6,20191212
7,url7,20191212

20191111.log
1,url1,20191111
2,url2,20191111
3,url3,20191111
4,url4,20191111
5,url5,20191111
6,url6,20191111
7,url7,20191111
20191101.log
1,url1,20191101
2,url2,20191101
3,url3,20191101
4,url4,20191101
5,url5,20191101
6,url6,20191101
7,url7,20191101
  • 创建分区表
create table test_partition2(id string,URL string,ct string) partitioned by (y string,m string,d string) row format delimited fields terminated by ',';
  • 添加数据
load data local inpath '/root/demo01/20191101.log' into table test_partition2 partition(y='2019',m='11',d='01');
load data local inpath '/root/demo01/20191111.log' into table test_partition2 partition(y='2019',m='11',d='11');
load data local inpath '/root/demo01/20191212.log' into table test_partition2 partition(y='2019',m='12',d='12');
load data local inpath '/root/demo01/20201128.log' into table test_partition2 partition(y='2020',m='11',d='28');
load data local inpath '/root/demo01/20201129.log' into table test_partition2 partition(y='2020',m='11',d='29');
load data local inpath '/root/demo01/20201130.log' into table test_partition2 partition(y='2020',m='11',d='30');
4.2 动态分区

静态分区添加数据需要手动添加,并且不能处理已经存在的混乱表格,引入动态分区表

实施流程(创建一个二级分区的动态分区表):

  • 准备数据
1,lisi,Shanghai,1024,
2,ycy,Shanghai,1024
3,ym,Beijing,1025
4,Yangzi,Beijing,1026
5,Yangguo,shenzhen,1122
6,mayun,shenzhen,1122
7,mbg,Shanghai,1024
8,marong,shenzhen,1025
  • 建一个普通表,将数据导入
create table test_dongtai_tmp (id int ,name string,city string,dt string) row format delimited fields terminated by ',';
--建表

load data local inpath '/root/anli/log1/dongtai.fs' into table test_dongtai_tmp;
--加载数据
  • 创建动态表
create table test_dongtai (id int,name string,city string) partitioned by(p_city string ,p_dt string); 
  • 开启动态分区
set hive.exec.dynamic.partition=true ;
set hive.exec.dynamic.partition.mode=nonstrick;
  • 向动态分区表中添加数据
insert into test_dongtai partition(p_city,p_dt) select id,name,city,city,dt from test_dongtai_tmp ; 
  • 查看数据

[外链图片转存中…(img-u5FO4u1u-1607216353298)]

注意事项

  • 为避免数据冗余,分区数据可以单独存在
  • 开启动态分区当前会话有效,经常使用需要修改配置文件

5.分桶表

5.1 分桶表
  • 分桶表原理

    • 分桶表类似于将一个表(或一个分区)使用MapReduce中分区器的分区方法,通过hashcode或者类似算法,将数据依据某属性,分割成n等分,并分装到不同文件中;
    • 当有读取请求或join请求时,可以直接在相应分桶文件中进行操作,减少了遍历范围,提高效率。
  • 分桶表的使用

  1. 创建普通表,导入数据

    create table tb_stu(id int, name string)
    row format delimited fields terminated by '\t';
    load data local inpath "/root/anli/stu/" into  table tb_stu ;
    
  2. 创建分桶表

    create table test_buck(id int, name string)
    clustered by(id) into 4 buckets
    row format delimited fields terminated by '\t';
    
  3. 开启分桶功能

    set hive.enforce.bucketing=true;     -- 开启分桶
    set mapreduce.job.reduces=-1;		 -- 默认数量
    
  4. 使用insert into的方式导入数据 到 分桶表中

    insert into table test_buck
    select id, name from tb_stu;
    
  5. 分桶完成

[外链图片转存中…(img-JEdQAoUZ-1607216353300)]

5.2 抽样查询语句
 select * from  buck_stu tablesample(bucket 1 out of 3 on id);
 select * from  buck_stu tablesample(bucket 2 out of 3 on id);
 select * from  buck_stu tablesample(bucket 3 out of 3 on id);
 
 --将数据随机分为n份,数量不一定相同,但每份的数据不会重复
 --以上语句查询出来的结果是没有重复的

6.逻辑顺序/分组本质

  • SQL语句逻辑执行顺序:

    select
    *			(4
    from		(1
    tb_name
    where     	(2
    group by	(3
    having		(5
    order  by	(6
    limit		(7
    
  • 分组本质

    • 不分组时,打印区(上面的4号区)接收的数据时行数据对象,可以使用处理行数据的函数进行操作;
    • 数组使用group by 等进行分组后,传给打印区的数据就变成了行数组(集合)对象,需要使用处理行数组的函数(聚合函数)进行操作;
    • 常用的聚合函数有:max、min、sum、avg等等
    • 常用的行数据函数有:if、case when等

7.hive调试优化(***)

  • 企业数据处理方案:

[外链图片转存中…(img-OOj2DKf7-1607216353302)]

  • 常用优化方法:
    • 合理使用分区表和分桶表
    • 使用高效的存储格式
      • 列式存储—ORC和parquet
    • 小表join大表(MR程序中的map端join)
    • 开启map端聚合
    • 使用合理高效的SQL语句:
      • 避免count(distinct col)、select * 等操作
      • 避免笛卡尔积
    • 适当调整maptask和reducetask的个数(如处理窄长表,要适当增加maptask数量)
    • 在本地测试数据后再提交到yarn

四 常用语法

Hive中的SQL与MySQL的语法不完全相同,有些在MySQL中能够实现的操作,在Hive中不能执行

1.常用函数

1.1 工具类函数
--查看系统自带的所有函数
show functions;

--显示函数的用法
desc function 函数名;

--详细显示自带的函数的用法
desc function extended upper;
1.2 其他常用函数
--判断(正则表达式)
if(表达式,结果1,结果2)


--处理空值
nvl(,如果值为空返回的字符)


--当前数据库
current_database()


--在行内取最大值
greatest(1,2,...)


--添加一个临时判断列
case when then

 
--2020-11-27  这个月的第一天
select add_months(date_add(last_day('2020-11-27'),1),-1,'Y-M-dd');
select trunc('2020-11-27','MM');    --Q求季度第一天;YY求年第一天
--这天的所在周 的周一
select date_add('2020-11-27',(2-dayofweek('2020-11-27')));
select date_sub('2020-11-27',dayofweek('2020-11-27')-2);


--子查询;
with t as (查询结果1) , [ t2 as (查询结果2) ] [, ...] 
select ... from ... ;


--创建数组 数组是hive中的一种集合数据类型  和 java中的数组一样;
array(ele1 , ele2...)  
select array(1,2,3,4) ;
select array(1,2,3,4)[index] ;


--判断 数组中是否包含某个元素;
array_contains(arr , element) ;
select array_contains(array('a','ab','abc','abcd'),'aa') ;


--转换 大小写
upper
lower 
select lower('ABC') ;
select upper('ABC') ;


--切割 返回数组
split(str , seq)
select split("hello_tom_jim","_")[0] ;


--取出收尾空格
trim(str)
select trim("  hello  ") ;


--生成一串随机字符
select uuid() ;
229e4f73-614d-4940-8043-00ac454588df 


--替换字符串(hive中没有replaceAll)
replace(字符串 , 要替换的子串 , 替换的新str) 
select replace(uuid() ,'-','') ;
229e4f73614d4940804300ac454588df 


--截取字符串
substr(str ,起始位置1开始 [,长度])            
substring  和上面的函数一样


--截取第n个分隔符之前的字符(从字符串str返回分隔符delim出现次数count之前的子字符串)
substring_index(str, delim, count)
select substring_index('229e4f73-614d-4940-8043-00ac454588df','-',0);
啥也没有
select substring_index('229e4f73-614d-4940-8043-00ac454588df','-',1);
229e4f73
select substring_index('229e4f73-614d-4940-8043-00ac454588df','-',3);
229e4f73-614d-4940


--正则表达式(使用正则表达式剔除最后一个特殊符号)
select if(
    regexp_extract("ab_ab_","(.*?)_$",1)="",
    "ab_ab_",
    regexp_extract("ab_ab_","(.*?)_$",1));
1.3 语法技巧
  1. 在进行分组操作后,可以使用max(case when then)的方法,获取非分组字段的数据;
  2. 使用面向对象的思想,理解SQL语句;

2.窗口函数(***)

  • 核心思想:

    1. 使用over()将数据分割为数个窗口,over内处理的是行数据,可以进行分割(partition by)、排序(order by)、截取行(between and)等操作;
    2. 使用order by时需要注意,处理的内容为该窗口起始行到当前行的数据(sum、max等操作);
    3. ntile函数将窗口数据分为n等份,返回的是1-n的编号,具体操作查看演示需求5;
  • 相关函数

    OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化
    
    --行处理函数
    CURRENT ROW:当前行  current row
    n PRECEDING:往前n行数据  n preceding
    n FOLLOWING:往后n行数据  n following
    UNBOUNDED PRECEDING 表示从前面的起点 		unbound preceding
    UNBOUNDED FOLLOWING表示到后面的终点			unbound following
    
    --类聚合函数,窗口函数特有函数,其他地方不能使用
    LAG(col,n):往前第n行数据  lag
    LEAD(col,n):往后第n行数据 lead
    NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。  ntile(5)
    
  • 使用演示:

    准备数据:name,orderdate,cost
    jack,2017-01-01,10
    tony,2017-01-02,15
    jack,2017-02-03,23
    tony,2017-01-04,29
    jack,2017-01-05,46
    jack,2017-04-06,42
    tony,2017-01-07,50
    jack,2017-01-08,55
    mart,2017-04-08,62
    mart,2017-04-09,68
    neil,2017-05-10,12
    mart,2017-04-11,75
    neil,2017-06-12,80
    mart,2017-04-13,94
    
    建表并插入数据:
    create table test_win (name string, odt string, cost int) 
    row format delimited fields terminated by ',';
    

load data local inpath ‘/root/anli/windows/windows.txt’ into table test_win;

需求:
(1)查询在2017年4月份购买过的顾客及总人数
select name , count(1) over() as countP 
from test_win 
where split(odt,'-')[1] = '04' 
group by name ;
+-------+---------+
| name  | countp  |
+-------+---------+
| mart  | 2       |
| jack  | 2       |
+-------+---------+

(2)查询顾客的购买明细及月购买总额
select *,sum(cost) over(partition by name,month(odt)) 
from test_win ;
+----------------+---------------+----------------+---------------+
| test_win.name  | test_win.odt  | test_win.cost  | sum_window_0  |
+----------------+---------------+----------------+---------------+
| jack           | 2017-01-05    | 46             | 111           |
| jack           | 2017-01-08    | 55             | 111           |
| jack           | 2017-01-01    | 10             | 111           |
| jack           | 2017-02-03    | 23             | 23            |
| jack           | 2017-04-06    | 42             | 42            |
| mart           | 2017-04-13    | 94             | 299           |
| mart           | 2017-04-11    | 75             | 299           |
| mart           | 2017-04-09    | 68             | 299           |
| mart           | 2017-04-08    | 62             | 299           |
| neil           | 2017-05-10    | 12             | 12            |
| neil           | 2017-06-12    | 80             | 80            |
| tony           | 2017-01-04    | 29             | 94            |
| tony           | 2017-01-02    | 15             | 94            |
| tony           | 2017-01-07    | 50             | 94            |
+----------------+---------------+----------------+---------------+

(3)上述的场景,要将cost按照日期进行累加
select *,sum(cost) over(partition by name,month(odt) order by odt) 
from test_win ;
+----------------+---------------+----------------+---------------+
| test_win.name  | test_win.odt  | test_win.cost  | sum_window_0  |
+----------------+---------------+----------------+---------------+
| jack           | 2017-01-01    | 10             | 10            |
| jack           | 2017-01-05    | 46             | 56            |
| jack           | 2017-01-08    | 55             | 111           |
| jack           | 2017-02-03    | 23             | 23            |
| jack           | 2017-04-06    | 42             | 42            |
| mart           | 2017-04-08    | 62             | 62            |
| mart           | 2017-04-09    | 68             | 130           |
| mart           | 2017-04-11    | 75             | 205           |
| mart           | 2017-04-13    | 94             | 299           |
| neil           | 2017-05-10    | 12             | 12            |
| neil           | 2017-06-12    | 80             | 80            |
| tony           | 2017-01-02    | 15             | 15            |
| tony           | 2017-01-04    | 29             | 44            |
| tony           | 2017-01-07    | 50             | 94            |
+----------------+---------------+----------------+---------------+

(4)查询顾客上次的购买时间
select * , lag(odt,1,'第一次购买') over(partition by name order by odt) 
from test_win;
+----------------+---------------+----------------+---------------+
| test_win.name  | test_win.odt  | test_win.cost  | lag_window_0  |
+----------------+---------------+----------------+---------------+
| jack           | 2017-01-01    | 10             | 第一次购买         |
| jack           | 2017-01-05    | 46             | 2017-01-01    |
| jack           | 2017-01-08    | 55             | 2017-01-05    |
| jack           | 2017-02-03    | 23             | 2017-01-08    |
| jack           | 2017-04-06    | 42             | 2017-02-03    |
| mart           | 2017-04-08    | 62             | 第一次购买         |
| mart           | 2017-04-09    | 68             | 2017-04-08    |
| mart           | 2017-04-11    | 75             | 2017-04-09    |
| mart           | 2017-04-13    | 94             | 2017-04-11    |
| neil           | 2017-05-10    | 12             | 第一次购买         |
| neil           | 2017-06-12    | 80             | 2017-05-10    |
| tony           | 2017-01-02    | 15             | 第一次购买         |
| tony           | 2017-01-04    | 29             | 2017-01-02    |
| tony           | 2017-01-07    | 50             | 2017-01-04    |
+----------------+---------------+----------------+---------------+

(5)查询前20%时间的订单信息
select *,ntile(5) over(order by odt) 
from test_win ;
+----------------+---------------+----------------+-----------------+
| test_win.name  | test_win.odt  | test_win.cost  | ntile_window_0  |
+----------------+---------------+----------------+-----------------+
| jack           | 2017-01-01    | 10             | 1               |
| tony           | 2017-01-02    | 15             | 1               |
| tony           | 2017-01-04    | 29             | 1               |
| jack           | 2017-01-05    | 46             | 2               |
| tony           | 2017-01-07    | 50             | 2               |
| jack           | 2017-01-08    | 55             | 2               |
| jack           | 2017-02-03    | 23             | 3               |
| jack           | 2017-04-06    | 42             | 3               |
| mart           | 2017-04-08    | 62             | 3               |
| mart           | 2017-04-09    | 68             | 4               |
| mart           | 2017-04-11    | 75             | 4               |
| mart           | 2017-04-13    | 94             | 4               |
| neil           | 2017-05-10    | 12             | 5               |
| neil           | 2017-06-12    | 80             | 5               |
+----------------+---------------+----------------+-----------------+
with t as 
(select *,ntile(5) over(order by odt) num
from test_win )
select t.name,t.odt,t.cost 
from t 
where num=1;
+---------+-------------+---------+
| t.name  |    t.odt    | t.cost  |
+---------+-------------+---------+
| jack    | 2017-01-01  | 10      |
| tony    | 2017-01-02  | 15      |
| tony    | 2017-01-04  | 29      |
+---------+-------------+---------+
```

3.关联查询

注意

  • 条件限制语句要用on,不能用where,使用where会产生笛卡尔积影响效率

  • 联合查询union:会自动根据某个字段进行联合(前提是列的数量要相同)

  • left semi join:就是把左表中左右两表都存在的字段进行输出,与select id from tb_b;效果相同

用法演示:

image-20201201214007391 image-20201201214032142
-   join
-   inner join
--两者用法基本相同,都是内连接,只显示两表都有的数据
select * from tb_a join tb_b on tb_a.id=tb_b.id;
+----------+------------+----------+------------+
| tb_a.id  | tb_a.name  | tb_b.id  | tb_b.name  |
+----------+------------+----------+------------+
| 1        | a          | 1        | zss        |
| 2        | b          | 2        | lss        |
| 3        | c          | 3        | www        |
| 1        | a          | 1        | xxx        |
| 2        | b          | 2        | yyy        |
+----------+------------+----------+------------+
select * from tb_b inner join tb_a on tb_a.id=tb_b.id;
+----------+------------+----------+------------+
| tb_b.id  | tb_b.name  | tb_a.id  | tb_a.name  |
+----------+------------+----------+------------+
| 1        | zss        | 1        | a          |
| 2        | lss        | 2        | b          |
| 3        | www        | 3        | c          |
| 1        | xxx        | 1        | a          |
| 2        | yyy        | 2        | b          |
+----------+------------+----------+------------+


-   left/right join
select * from tb_a right join tb_b on tb_a.id=tb_b.id;
+----------+------------+----------+------------+
| tb_a.id  | tb_a.name  | tb_b.id  | tb_b.name  |
+----------+------------+----------+------------+
| 1        | a          | 1        | zss        |
| 2        | b          | 2        | lss        |
| 3        | c          | 3        | www        |
| 1        | a          | 1        | xxx        |
| 2        | b          | 2        | yyy        |
| NULL     | NULL       | 4        | zzz        |
+----------+------------+----------+------------+


-   full join 
--与inner join相反,full join补全所有空白
select * from tb_a full join tb_b on tb_a.id=tb_b.id;
+----------+------------+----------+------------+
| tb_a.id  | tb_a.name  | tb_b.id  | tb_b.name  |
+----------+------------+----------+------------+
| 1        | a          | 1        | xxx        |
| 1        | a          | 1        | zss        |
| 2        | b          | 2        | yyy        |
| 2        | b          | 2        | lss        |
| 3        | c          | 3        | www        |
| NULL     | NULL       | 4        | zzz        |
+----------+------------+----------+------------+


-   union 
select * from tb_a  union select * from tb_b;
+---------+-----------+
| _u1.id  | _u1.name  |
+---------+-----------+
| 1       | a         |
| 1       | xxx       |
| 1       | zss       |
| 2       | b         |
| 2       | lss       |
| 2       | yyy       |
| 3       | c         |
| 3       | www       |
| 4       | d         |
| 4       | zzz       |
+---------+-----------+
--union all 不会去重,并且不会排序
select * from tb_a  union all select * from tb_b
+---------+-----------+
| _u1.id  | _u1.name  |
+---------+-----------+
| 1       | zss       |
| 2       | lss       |
| 3       | www       |
| 1       | xxx       |
| 2       | yyy       |
| 4       | zzz       |
| 4       | d         |
| 1       | a         |
| 2       | b         |
| 3       | c         |
+---------+-----------+


-   left semi join 
select * from tb_b left semi join tb_a on tb_a.id=tb_b.id;
+----------+------------+
| tb_b.id  | tb_b.name  |
+----------+------------+
| 1        | zss        |
| 2        | lss        |
| 3        | www        |
| 1        | xxx        |
| 2        | yyy        |
+----------+------------+

4.行/列转换

4.1 列转行
  • 使用函数:
collect_set		-- 将收集的多行数据聚集成一个数组集合(去重)
collect_list	-- 这两个都是聚合函数(list不会去重)
concat			-- 拼接 参数是可变参数 将所有单个字符串拼接为一个字符串
concat_ws		-- 参数一 拼接符;参数二 可变个数的字符串/数组集合
  • 使用演示:
--准备数据:
《八佰》	战争
《八佰》	动作
《八佰》	抗日
《八佰》	剧情
《姜子牙》	动画
《姜子牙》	神话
《姜子牙》	科幻
《姜子牙》	动作
《姜子牙》	伦理
《战狼2》	战争
《战狼2》	动作
《战狼2》	灾难

--建表添加数据:
create table  tb_movie(
name string ,
typ string 
)
row format delimited fields terminated by '\t' ;
load data local inpath "/root/anli/movie" into table tb_movie ;

--按照电影名聚合属性(列转行)
select name,concat_ws(",",collect_list(typ)) from tb_movie group by name;

+------------------+-------------------+
| test_movie.name  | test_movie.mtype  |
+------------------+-------------------+
| 《八佰》             | 战争,动作,抗日,剧情       |
| 《姜子牙》            | 动画,神话,科幻,动作,伦理    |
| 《战狼2| 战争,动作,灾难          |
+------------------+-------------------+

--将结果输出为表格
create table test_movie as select name,concat_ws(",",collect_list(typ)) mtype from tb_movie group by name;
4.2 行转列(***)
  • 使用函数:
explode(split(categorys,","))  -- 将字符串切割成数组
lateral view 				   -- 侧窗口函数
  • 使用演示:
以上表最后输出的结果为原始表,将其恢复原状

--使用explode和lateral view进行转换(行转列)
select name , tp from test_movie lateral view explode(split(mtype,','))t as tp;

+----------+-------+
|   name   |  tp   |
+----------+-------+
| 《八佰》   | 战争  |
| 《八佰》   | 动作  |
| 《八佰》   | 抗日  |
| 《八佰》   | 剧情  |
| 《姜子牙》  | 动画  |
| 《姜子牙》  | 神话  |
| 《姜子牙》  | 科幻  |
| 《姜子牙》  | 动作  |
| 《姜子牙》  | 伦理  |
| 《战狼2| 战争  |
| 《战狼2| 动作  |
| 《战狼2| 灾难  |
+----------+-------+

--explode可以单独使用
select explode(split(mtype,',')) from test_movie;

+------+
| col  |
+------+
| 战争   |
| 动作   |
| 抗日   |
| 剧情   |
| 动画   |
| 神话   |
| 科幻   |
| 动作   |
| 伦理   |
| 战争   |
| 动作   |
| 灾难   |
+------+

5.排序及编号

  • 基本:
    • order by 全局排序
    • desc 降序;
    • asc 升序(默认);
5.1 分区排序
  • 使用函数:

    distribute by		--将查询结果按指定字段分区
    sort by				--区内数据排序 
    
  • 使用方法:

    • hive在执行SQL的时候默认是一个MapReduce任务;

    • distribute by 不能指定分区数量,分区数量是依据reduce的数量确定的;

    • 直接打印不能直观看出是否分区(实际上数据已经分开);

      image-20201202204945756
    • 一般配合insert overwrite local directory '/root/anli/out2/' select * from test_win distribute by name; 输出到本地或hdfs中进行查看;

      image-20201202205159662
    • sort by 是对区内的数据进行排序

  • cluster by :

    • distribute bysort by 同时使用,且分区和排序使用同一字段,且是升序时,可以简写为cluster by

      select * from tb_x distribute by name sort by name desc;
      --可简写为:
      select * from tb_x cluster by name;
      --注意只能升序使用,降序不能使用;
      
5.2 编号函数
  • 核心用法:

    • 编号函数后面可以接窗口函数
    • row_number() :单纯的添加序号;
    • rank() :会根据排序的字段,排名相同的会给相同序号,并列的序号会被空出;
    • dense_rank() :同rank,相同排名会给相同序号,后面的序号不会留出并列的名次.
  • 使用演示(打地鼠):

    准备数据:
    u01,1,1
    u01,2,0
    u01,3,1
    u01,6,1
    u02,5,1
    u02,6,0
    u02,7,0
    u02,1,1
    u02,2,1
    u03,4,1
    u03,5,1
    u03,6,0
    u02,3,0
    u02,4,1
    u02,8,1
    u01,4,1
    u01,5,0
    u02,9,1
    u03,1,1
    u03,2,1
    u03,3,1
    
    建表并导入数据:
    create table test_dds (uid string, num int, tf int ) 
    row format delimited fields terminated by ',';
    load data local inpath '/root/anli/dds/dds.txt' into table test_dds;
    
    需求:查询连续打中超过2次的人的最高纪录;
    
    with t2 as 
    (select
    uid,diff,count(1) lianxu
    from
    (select
    *,num-rn diff
    from
    (select 
    uid,num,
    row_number() over(partition by uid order by num) rn
    from test_dds 
    where tf=1) t) t1
    group by uid,diff
    having lianxu>=2 )
    select uid,max(lianxu)
    from t2
    group by uid
    ;
    +------+------+
    | uid  | _c1  |
    +------+------+
    | u01  | 2    |
    | u02  | 2    |
    | u03  | 5    |
    +------+------+
    
  • 案例二:

    准备数据:
    孙悟空,语文,87
    孙悟空,数学,95
    娜娜,英语,84
    宋宋,语文,64
    孙悟空,英语,68
    宋宋,英语,84
    婷婷,语文,65
    娜娜,语文,94
    宋宋,数学,86
    婷婷,数学,85
    娜娜,数学,56
    婷婷,英语,78
    
    建表,导数据:
    create table test_sub (name string,subject string , score int)
    row format delimited fields terminated by ',';
    load data local inpath '/root/anli/sub/sub.txt' into table test_sub;
    +----------------+-------------------+-----------------+
    | test_sub.name  | test_sub.subject  | test_sub.score  |
    +----------------+-------------------+-----------------+
    | 孙悟空          | 语文               | 87              |
    | 孙悟空          | 数学               | 95              |
    | 娜娜            | 英语               | 84              |
    | 宋宋            | 语文               | 64              |
    | 孙悟空          | 英语               | 68              |
    | 宋宋            | 英语               | 84              |
    | 婷婷            | 语文               | 65              |
    | 娜娜            | 语文               | 94              |
    | 宋宋            | 数学               | 86              |
    | 婷婷            | 数学               | 85              |
    | 娜娜            | 数学               | 56              |
    | 婷婷            | 英语               | 88              |
    +----------------+-------------------+-----------------+
    
    需求1:按照科目进行排名
    select *,row_number() over(partition by subject order by score) from test_sub;
    +----------------+-------------------+-----------------+----------------------+
    | test_sub.name  | test_sub.subject  | test_sub.score  | row_number_window_0  |
    +----------------+-------------------+-----------------+----------------------+
    | 娜娜           | 数学               | 56              | 1                    |
    | 婷婷           | 数学               | 85              | 2                    |
    | 宋宋           | 数学               | 86              | 3                    |
    | 孙悟空         | 数学               | 95              | 4                    |
    | 孙悟空         | 英语               | 68              | 1                    |
    | 宋宋           | 英语               | 84              | 2                    |
    | 娜娜           | 英语               | 84              | 3                    |
    | 婷婷           | 英语               | 88              | 4                    |
    | 宋宋           | 语文               | 64              | 1                    |
    | 婷婷           | 语文               | 65              | 2                    |
    | 孙悟空         | 语文               | 87              | 3                    |
    | 娜娜           | 语文               | 94              | 4                    |
    +----------------+-------------------+-----------------+----------------------+
    
    select *,rank() over(partition by subject order by score) from test_sub;
    +----------------+-------------------+-----------------+----------------+
    | test_sub.name  | test_sub.subject  | test_sub.score  | rank_window_0  |
    +----------------+-------------------+-----------------+----------------+
    | 娜娜           | 数学               | 56              | 1              |
    | 婷婷           | 数学               | 85              | 2              |
    | 宋宋           | 数学               | 86              | 3              |
    | 孙悟空         | 数学               | 95              | 4              |
    | 孙悟空         | 英语               | 68              | 1              |
    | 宋宋           | 英语               | 84              | 2              |
    | 娜娜           | 英语               | 84              | 2              |
    | 婷婷           | 英语               | 88              | 4              |
    | 宋宋           | 语文               | 64              | 1              |
    | 婷婷           | 语文               | 65              | 2              |
    | 孙悟空         | 语文               | 87              | 3              |
    | 娜娜           | 语文               | 94              | 4              |
    +----------------+-------------------+-----------------+----------------+
    
    select *,dense_rank() over(partition by subject order by score) from test_sub;
    +----------------+-------------------+-----------------+----------------+
    | test_sub.name  | test_sub.subject  | test_sub.score  | rank_window_0  |
    +----------------+-------------------+-----------------+----------------+
    | 娜娜           | 数学               | 56              | 1              |
    | 婷婷           | 数学               | 85              | 2              |
    | 宋宋           | 数学               | 86              | 3              |
    | 孙悟空         | 数学               | 95              | 4              |
    | 孙悟空         | 英语               | 68              | 1              |
    | 宋宋           | 英语               | 84              | 2              |
    | 娜娜           | 英语               | 84              | 2              |
    | 婷婷           | 英语               | 88              | 3              |
    | 宋宋           | 语文               | 64              | 1              |
    | 婷婷           | 语文               | 65              | 2              |
    | 孙悟空         | 语文               | 87              | 3              |
    | 娜娜           | 语文               | 94              | 4              |
    +----------------+-------------------+-----------------+----------------+
    
    
    需求2:将三科的成绩作为一行数据进行输出
    select name,
    max(if(subject='语文',score,0)) yuwen,
    max(if(subject='数学',score,0)) shuxue,
    max(if(subject='英语',score,0)) yingyu 
    from test_sub
    group by name;
    +-------+--------+---------+---------+
    | name  | yuwen  | shuxue  | yingyu  |
    +-------+--------+---------+---------+
    | 娜娜   | 94     | 56      | 84      |
    | 婷婷   | 65     | 85      | 88      |
    | 孙悟空 | 87     | 95      | 68      |
    | 宋宋   | 64     | 86      | 84      |
    +-------+--------+---------+---------+
    

6.自定义函数

6.1 反射函数(失败)

使用方法:

  • 创建maven项目
  • 建一个Java类,直接写一个方法
  • 打包
  • 上传到linux系统
  • add jar /test.jar(或者将jar包添加到 $HIVE_HOME/lib/目录下)
  • select reflect(‘cn.doit.ab.Demo’,‘test’,‘ab’);
6.2 自定义函数

1. 把自定义函数的jar上传到hdfs中.
  hdfs dfs -put lower.jar ‘hdfs:///path/to/hive_func’;
  2. 创建永久函数
  hive> create function xxoo_lower as ‘com._51doit.func.MyFunction’ using

jar ‘hdfs:///path/to/hive_func/lower.jar’
  3. 验证
  hive> select xxoo_lower(“Hello World”);
  hive> show functions;
  永久函数的删除也容易:
  hive> drop function xxoo_lower;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值