hive使用了类似SQL的查询语言HQL,因此容易将hive理解为数据库.其实hive和数据库除了有类似的查询语句之外,并没有其他地方类似.
hive数据类型 java数据类型 长度 例子
tinyint byte 1byte有符号整数 1
smalint short 2byte有符号整数 2
int int 4byte有符号整数 3
bigint long 8byte有符号整数 4
boolean boolean 布尔类型,true或false
float float 单精度浮点数 2.1
double double 双精度浮点数 2.2
string string 字符串 'aaa' "bbb"
timestamp 时间类型
binary 字节数组
hive的原子数据类型是可以进行隐式转换的,类似于java的类型转换,但是不会反向转换,除非使用cast
struct类型
struct{value1 string,value2 int}
map类型
键值对元组集合,键值对是 key1->value1
array类型
数组是一组具有相同类型和名称的变量集合 [value1, value2]
create table test(
name string,
friends array<string>,
children map<string, int>,
address struct<street:string, city:string>
)
row format delimited
fields terminated by ',' [列分隔符]
collection items terminated by '_' [map struct array 的分隔符]
map keys terminated by ':' [map中key value的分隔符]
lines terminated by '\n'; [行分隔符]
访问形式: friends[1] children['key'] address.city
创建数据库: create database if not exists db_name;
create database db_name location '/db_aname.db';--指定在hdfs上的路径
查询数据库: show databases;
show databases like 'order_*';
数据库信息: desc database db_name;
desc database extended db_name;
切换数据库: use db_name1;
修改数据库部分参数: alter database db_name set dbproperties('key'='value');
<-(*****!!!慎用!!!****)
删除数据库: drop database db_name; drop database if exists db_name;
如果数据库不为空,使用cascade: drop database db_name cascade;
(*****!!!慎用!!!****)->
建表语句:
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]
[stored as file_format]
[location hdfs_path]
解释:
create table 创建表,使用if not exists 规避表存在异常
external 创建外部表时使用,和内部表的区别在于,删除外部表时只删除元数据,不删除数据,内部表删除的时候元数据和数据一起被删除
comment 做注释说明
partitioned by 创建分区表,后面跟分区字段名称和类型
clustered by 创建分通表
sorted by 桶内排序,指定排序字段
(1)row format delimited
[fields terminated by char]
[collection items terminated by char]
[map keys terminated by char]
[lines terminated by char] 或
(2)serde serde_name [with serdeproperties (property_name=property_value, property_name=property_value, ...)]
用户在建表的时候可以自定义serde或者使用自带的serde,如果没有指定(1),将会使用自带的serde.serde是serialize/deserilize 的简称,目的是用于序列化和反序列化.
fields terminated by char : 数据列分隔符
collection items terminated by char: 集合元素分隔符
map keys terminated by char : map分隔符
lines terminated by char: 数据行分隔符
stored as 指定存储文件类型,常用的数据存储文件类型: sequencefile(二进制序列文件),textfile(文本),rcfile(列式存储格式文件)
location: 指定表在hdfs上的存储位置
like: 允许用户复制现有的表结构,但是不复制数据
例1:
create table if not exists table1(
id int comment "id",
name string comment "名称"
) row format delimited fields terminated by '\t';
例2:
create table if not exists table2 as select id,name from table1;
例3:
create table if not exists table3 like table2;
外部表和内部表(管理表)转换:
内部表=>外部表: alter table table1 set tblproperties('EXTERNAL'='TRUE');
外部表=>内部表: alter table table1 set tblproperties('EXTERNAL'='FALSE');
查看表结构: desc formatted table1
分区表:
create table if not exists table1(
id int comment "id",
name string comment "名称")
partitioned by (mon string)
row format delimited fields terminated by '\t';
LOAD DATA LOCAL INPATH '/path/to/local/files'
[OVERWRITE|INTO] TABLE test
PARTITION (country='CHINA')
加载数据: 如果是本地的数据,加local,文件会被拷贝到hdfs上,如果是hdfs的文件,则会直接移动文件.
into 是直接追加数据,overwrite是覆盖数据
增加分区: alter table table1 add partition(mon='202009')
增加多个分区: alter table table1 add partition(mon='202010') partition('202007')
删除分区: alter table table1 drop partition(mon='202008')
查看分区: show partitions table1
更新列: ALTER TABLE table_name
CHANGE [COLUMN] col_old_name col_new_name column_type
[COMMENT col_comment] [FIRST|AFTER column_name]
例: alter table test change a a1 int after b; 将a列名称更新为a1,类型替换为int,位置放在b列之后
增加和替换列:
ALTER TABLE table_name
ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...)
例: alter table test add columns(a1 int,b1 string); 添加a1和b1 两列在列末尾,分区列之前.
replace 则是替换表中所有的字段
插入数据: insert [into|overwrite] table test partition(par='xxx') values(xx,xx,xx);
insert [into|overwrite] table test partition(par='xxx') select xx,xx,xx from test2;
from table1
insert overwrite table test partition(par='xxx') select xx,xx where xx
insert into table test partition(par='xxx') select xx,xx where xx
数据导出:
insert overwrite local directory '/path/xxx.txt'
row format delimited fields terminated by '\t'
select * from table_name;
有local则是本地路径,没有local就是hdfs路径
清除表数据: truncate table test;
truncate只能删除管理表,不能删除外部表数据.
查询语句,没什么说的
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number]
group by 之后可以跟 having 对结果进行筛选,可以使用别名.
where 是针对表数据进行过滤,之后不能写聚合函数,而 having 可以
order by 全局排序,默认升序asc
distribute by 分区,结合sort by 使用,分区排序,写在sort by 之前
cluster by 当分区distribute by 的字段和sort by 的字段相同时,使用cluster by,但是只能是升序
查看所有函数: show functions;
查看函数用法: desc function func_name; desc function extended func_name;(带例子)
nvl(value,default_value) - Returns default value if value is null else returns value
判断value是否是null,如果是的话给个默认值,不是的话返回value本身
date_format('2020-08-08','yyyyMMdd'): 日期格式化 20200808
date_add('2020-08-08',1): 日期加1天 2020-08-09
date_sub('2020-08-08',1): 日期减1天 2020-08-07
将第二个参数设置为负数就可以起到另一个的作用
case when: 将sal低于1000的都加500,不符合条件的还是sal
select
id,(case when sal<1000 then sal+500 else sal end) as sal
from
emp;
行转列:
concat(str1,str2,str3....): 返回字符串拼接后的结果,有任一个参数为null,则返回null
concat_ws(分隔符,str1,str2,str3....): 第一个参数为分隔符,将字符串按照指定分隔符拼接,会跳过分隔符之后的任何null和空字符串
collect_set(col): 函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型
列转行:
explode(col): 将hive一列中复杂的array或者map拆分成多行
lateral view : LATERAL VIEW udtf(expression) tableAlias AS columnAlias,和udtf函数结合使用,将一列数据拆成多行,在此基础上可以对拆分后的数据进行聚合.
美团面试SQL:
from t_table
原始数据
label result
1001,1002,1003 1001:1,1002:3,1003:1,1004:1
需要数据
label result
1001 1
1003 1
找出label中元素result为1的
select
label1,result1
from
t_table as t1
lateral view explode(str_to_map(t1.result)) tmp as label1,result1
where result1=1 and instr(t1.label,label1)>0
str_to_map(text, delimiter1, delimiter2): 字面意思,将字符串转换成map,第一个分隔符是kv对和kv对之间的分隔符,默认',',第二个是kv之间的分隔符,默认是':'.
instr(str, substr) - 返回substr在str中第一次出现的位置,没有返回0
过程分解:
with t1 as
(select '1001,1002,1003' as pm1,'1001:1,1002:2,1003:1,1004:1' as pm2)
select mk,mv
from t1
lateral view explode(str_to_map(pm2)) tm2 as mk,mv
将'1001:1,1002:3,1003:1,1004:1' 爆炸开
mk mv
1001 1
1002 2
1003 1
1004 1
然后对结果 where 筛选
where mv=1 and instr(t1.pm1,mk)>0
over(): 指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化
current row: 当前行
n preceding: 往前n行数据
n following: 往后n行数据
unbounded: 起点, unbounded preceding 表示从前面的起点,unbounded following表示到后面的终点
lag(col,n): 往前第 n 行数据
lead(col,n): 往后第 n 行数据
ntile(n): 把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,ntile返回此行所属的组的编号
例子:
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
(1)查询17年4月份购买过的顾客及总人数
select
name,count(*) over()
from
test
where
substring(orderdate,1,7) = '2017-04'
group by
name;
jack 2
mart 2
(2)查询顾客的购买明细及月购买总额
select
name,orderdate,cost,sum(cost) over(partition by month(orderdate))
from
test;
jack 2017-01-01 10 205
tony 2017-01-02 15 205
tony 2017-01-04 29 205
jack 2017-01-05 46 205
tony 2017-01-07 50 205
jack 2017-01-08 55 205
jack 2017-02-03 23 23
jack 2017-04-06 42 341
mart 2017-04-08 62 341
mart 2017-04-09 68 341
mart 2017-04-11 75 341
mart 2017-04-13 94 341
neil 2017-05-10 12 12
neil 2017-06-12 80 80
(3)上述的场景,要将cost按照日期进行累加
select name,orderdate,cost,
sum(cost) over() as sample1,--所有行相加
sum(cost) over(partition by name) as sample2,--按name分组,组内数据相加
sum(cost) over(partition by name order by orderdate) as sample3,--按name分组,组内数据累加
sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row ) as sample4 ,--和sample3一样,由起点到当前行的聚合
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING and current row) as sample5, --当前行和前面一行做聚合
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING AND 1 FOLLOWING ) as sample6,--当前行和前边一行及后面一行
sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 --当前行及后面所有行
from test;
tony 2017-01-02 15 661 94 15 15 15 44 94
tony 2017-01-04 29 661 94 44 44 44 94 79
tony 2017-01-07 50 661 94 94 94 79 79 50
jack 2017-01-01 10 661 176 10 10 10 56 176
jack 2017-01-05 46 661 176 56 56 56 111 166
jack 2017-01-08 55 661 176 111 111 101 124 120
jack 2017-02-03 23 661 176 134 134 78 120 65
jack 2017-04-06 42 661 176 176 176 65 65 42
neil 2017-05-10 12 661 92 12 12 12 92 92
neil 2017-06-12 80 661 92 92 92 92 92 80
mart 2017-04-08 62 661 299 62 62 62 130 299
mart 2017-04-09 68 661 299 130 130 130 205 237
mart 2017-04-11 75 661 299 205 205 143 237 169
mart 2017-04-13 94 661 299 299 299 169 169 94
(4)查询顾客上次的购买时间
select
name,orderdate,cost,
lag(orderdate,1,'1900-01-01') over(partition by name order by orderdate ) as time1, lag(orderdate,2) over (partition by name order by orderdate) as time2
from test;
lag(col,n,default_value): 第三个参数传默认值,不传默认为null
tony 2017-01-02 15 1900-01-01 NULL
tony 2017-01-04 29 2017-01-02 NULL
tony 2017-01-07 50 2017-01-04 2017-01-02
jack 2017-01-01 10 1900-01-01 NULL
jack 2017-01-05 46 2017-01-01 NULL
jack 2017-01-08 55 2017-01-05 2017-01-01
jack 2017-02-03 23 2017-01-08 2017-01-05
jack 2017-04-06 42 2017-02-03 2017-01-08
neil 2017-05-10 12 1900-01-01 NULL
neil 2017-06-12 80 2017-05-10 NULL
mart 2017-04-08 62 1900-01-01 NULL
mart 2017-04-09 68 2017-04-08 NULL
mart 2017-04-11 75 2017-04-09 2017-04-08
mart 2017-04-13 94 2017-04-11 2017-04-09
(5)查询前20%时间的订单信息
select * from (
select name,orderdate,cost, ntile(5) over(order by orderdate) sorted
from business
) t
where sorted = 1;
以下为不加 sorted=1 的结果
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
rank() 排序相同时会重复,总数不变 1 2 3 3 5
dense_rank() 排序相同时会重复,总数会减少 1 2 2 3 4
row_number() 根据顺序计算 1 2 3 4 5
select
subject,score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rmp
from
score;
subject score rank dense_rank row_number
数学 95 1 1 1
数学 86 2 2 2
数学 85 3 3 3
数学 56 4 4 4
英语 84 1 1 1
英语 84 1 1 2
英语 78 3 2 3
英语 68 4 3 4
语文 94 1 1 1
语文 87 2 2 2
语文 65 3 3 3
语文 64 4 4 4
hive支持的存储数据的格式主要有: textfile sequencefile orc parquet