[WITH CommonTableExpression (, CommonTableExpression)*] (Note: Only available
starting with Hive 0.13.0)
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]
select * from tb_test;
# 一般为了性能,都会选择所需要字段进行查询,尽力尽力避免全表查询,特别HQL属于海量数据处理,全表查询会给集群带来巨大压力,耗时也会很久
select age, name from tb_test;
别名可以看作是一个简称,类似于C语言中的宏定义,可以将一个字段名、查询结果集都是用别名代称。
但需要注意,别名的定义要在使用前,所以需要注意sql语句的执行顺序
select
xxxx,yyyy
from
where
group by
having
limit
整体是先执行from,然后是where,然后是查询字段,然后是group by,having,limit。所以如果需要使用别名但不确定的话,先确定sql执行顺序。
使用嵌套子查询时,hql中使用括号包起来的部分请一定一定带上别名,否则会出错
- A+B A和B 相加
- A-B A减去B
- A*B A和B 相乘
- A/B A除以B
- A%B A对B取余
- A&B A和B按位取与
- A|B A和B按位取或
- A^B A和B按位取异或
- ~A A按位取反
select age+1 from tb_person;
select count(*) as cnt from tb_person;
# count(1)比count(*)要快,如果要对字段计数,内部加distinct时谨慎,这样会比较耗时,建议改为分组后再count(1)
select count(1) as cnt from tb_person;
select max(age) as age_max from tb_person;
select min(age) from tb_person;
select sum(salary) as total_salary from tb_person;
select avg(age) as age_average from tb_person;
注意,如果查询结果需要用到聚合函数,进行嵌套子查询时,一般都是在最后一层时再计算,这样可以有比较清晰的查询逻辑
主要用于限制返回结果条数(行数)
# 返回10条
select * from tb_test limit 10;
# 第一个数字0,是指起始行数,一般从0行开始计算,第二个是返回的行数。大家在网页和app看到的分页加载就是使用limit来进行数据切割并返回的,而且大部分一页数据是10或者15条。
select * from tb_test limit 9, 10;
where的用法和正常的sql规范用法一致,属于限定条件,同时having也是一样,可以针对group by之后数据继续限定
select age, name from tb_person where age > 23;
- A=B 基本数据类型 如果A等于B则返回TRUE,反之返回FALSE
- A<=>B 基本数据类型 如果A和B都为NULL,则返回TRUE,其他的和等号(=)操作符的结果一致,如果任一为NULL则结果为NULL
- A<>B, A!=B 基本数据类型 A或者B为NULL则返回NULL;如果A不等于B,则返回TRUE,反之返回FALSE
- A
- A<=B 基本数据类型 A或者B为NULL,则返回NULL;如果A小于等于B,则返回TRUE,反之返回FALSE
- A>B 基本数据类型 A或者B为NULL,则返回NULL;如果A大于B,则返回TRUE,反之返回FALSE
- A>=B 基本数据类型 A或者B为NULL,则返回NULL;如果A大于等于B,则返回TRUE,反之返回FALSE
- A [NOT] BETWEEN B AND C 基本数据类型 如果A,B或者C任一为NULL,则结果为NULL。如果A的值大于等于B而且小于或等于C,则结果为TRUE,反之为FALSE。如果使用NOT关键字则可达到相反的效果。
- A IS NULL 所有数据类型 如果A等于NULL,则返回TRUE,反之返回FALSE
- A IS NOT NULL 所有数据类型 如果A不等于NULL,则返回TRUE,反之返回FALSE
- IN(数值1, 数值2) 所有数据类型 使用 IN运算显示列表中的值
- A [NOT] LIKE B STRING 类型 B是一个SQL下的简单正则表达式,如果A与其匹配的话,则返回TRUE;反之返回FALSE。B的表达式说明如下:‘x%’表示A必须以字母‘x’开头,‘%x’表示A必须以字母’x’结尾,而‘%x%’表示A包含有字母’x’,可以位于开头,结尾或者字符串中间。如果使用NOT关键字则可达到相反的效果。
- A RLIKE B, A REGEXP B STRING 类型 B是一个正则表达式,如果A与其匹配,则返回TRUE;反之返回FALSE。匹配使用的是JDK中的正则表达式接口实现的,因为正则也依据其中的规则。例如,正则表达式必须和整个字符串A相匹配,而不是只需与其字符串匹配。
官方文档:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
select * from emp where sal =5000;
select * from emp where sal between 500 and 1000;
select * from emp where comm is null;
select * from emp where sal IN (1500, 5000);
select * from emp where sal LIKE '2%';
select * from emp where sal LIKE '_2%';
select * from emp where sal RLIKE '[2]';
- AND 逻辑并
- OR 逻辑或
- NOT 逻辑否
注意拼接join是,on不能跟or,hive中on不支持不等连接,也就是一般都是x join y on x.id=y.id
select * from emp where sal>1000 and deptno=30;
select * from emp where sal>1000 or deptno=30;
select * from emp where deptno not IN(30, 20);
# 注意这里的字段访问,只能直接访问分组的字段t.deptno。其他都是通过聚合函数avg()进行访问和处理的
select t.deptno, avg(t.sal) avg_sal from emp t group by t.deptno;
select t.deptno, t.job, max(t.sal) max_sal from emp t group by
t.deptno, t.job;
select deptno, avg(sal) from emp group by deptno;
# 注意这里别名avg_sal 的定义,由于查询字段执行要比having更早,所以having可以使用这个别名
select deptno, avg(sal) avg_sal from emp group by deptno having
avg_sal > 2000;
emp join dept on emp.dptno=dept.dptno
hive支持join,在旧版本不支持不等值join,新版本3.1.2中是支持不等值join的。也就是在on那里,可以把=换成!=或者其他限定条件
由于join多张表时,sql语句可能会非常长,使用别名来替代一串sql语句或者字段是非常有利于sql语句的阅读和维护使用的。
而且,如果使用表名前缀可以提高执行效率
select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno = d.deptno;
2个连接的表中都存在与连接条件匹配的数据,这些数据才会被保留下来
# 注意,使用别名时,最好使用as来显示标识出这是别名,算是一种好的编码习惯
# 过长的sql语句可以换行显示,这样看起来可能会更有利于阅读一些
select
e.empno,
e.ename,
d.deptno
from
emp as e
join dept as d
on
e.deptno = d.deptno;
join左边表符合where子句所有数据被返回,也就是以左边为主
select
e.empno,
e.ename,
d.deptno
from emp as e
left join
dept as d
on e.deptno = d.deptno;
join右侧符合where条件的所有数据都会返回,也就是以右侧数据为主
select
e.empno,
e.ename,
d.deptno
from emp as e
right join
dept as d
on e.deptno = d.deptno;
将返回join左右2侧表中,所有符合where条件的数据。没有则使用null代替
select
e.empno,
e.ename,
d.deptno
from
emp as e
full join
dept as d
on
e.deptno = d.deptno;
SELECT
e.ename,
d.deptno,
l.loc_name
FROM
emp as e
JOIN
dept as d
ON
d.deptno = e.deptno
JOIN
location as l
ON
d.loc = l.loc;
hive内部机制,一般一个join对象启动一个mapreduce任务,所以本案例中会有2个mapreduce任务。注意这里的执行顺序也是先 e 和 d ,然后是这个结果再和 l 进行处理。
select
empno,
dname
from
emp,
dept;
注意,使用查询时,需要i尽力避免笛卡尔积产生,除非能够确认其中一张表是小表,否则数据量会暴增。
select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno
= d.deptno or e.ename=d.ename; 错误的
在做实际数据处理时,经常需要对数据进行排序,最多的,最高的,最少的等等,这时候就需要处理几个问题:
如何排序
根据什么排序
如何提升排序速度进而加快查询速度
# 默认就是asc升序,所以不需要单独设置
select * from emp order by sal;
select * from emp order by sal desc;
# 使用别名有一个前提,就是别名需要先执行,从此前sql语句的执行顺序可知字段查询只排在from之后,所以order by的时候是可以使用的。
select
ename,
sal*2 as twosal
from
emp
order by twosal;
# 多个字段排序,就和现实中排序一样,先按照第一个标准排序,排完之后再按照第二个标准排序。
select
ename,
deptno,
sal
from
emp
order by deptno, sal ;
set mapreduce.job.reduces=3;
set mapreduce.job.reduces;
select
*
from
emp
sort by
empno desc;
insert overwrite local directory '/hive/sortby_result'
select * from emp sort by deptno desc;
set mapreduce.job.reduces=3;
insert overwrite local directory '/root/data/distribute-result'
select
*
from
emp
distribute by deptno
sort by empno desc;
select * from emp cluster by deptno;
select * from emp distribute by deptno sort by deptno;
# 注意这里和分区不一样,分桶是按照
create table buck_demo(
id int,
name string
)
clustered by(id)
into 4 buckets
row format delimited fields terminated by '\t';
desc formatted buck_demo;
create table stu(id int, name string)
row format delimited fields terminated by '\t';
load data local inpath '/data/student.txt' into table stu;
set hive.enforce.bucketing=true; -- 开启分桶
set mapreduce.job.reduces=-1; -- 默认reduce个数
insert into table buck_demo
select id, name from stu;
# 就是把数据分成四份,注意不是均等划分,有的可能为空,取其中一份的数据。因为整体是随机划分的,所以可以保证随机性。
select
*
from
buck_demo
tablesample(bucket 1 out of 4 on id);
y必须是table总bucket数的倍数或者因子。
hive根据y的大小,决定抽样的比例。
例如,table总共分了4份,当y=2时,抽取(4/2=)2个bucket的数据,当y=8时,抽取(4/8=)1/2个bucket的数据。
x表示从哪个bucket开始抽取,如果需要取多个分区,以后的分区号为当前分区号加上y。
例如,table总bucket数为4,tablesample(bucket 1 out of 2),表示总共抽取(4/2=)2个bucket的数据,抽取第1(x)个和第3(x+y)个bucket的数据。
注意:x的值必须小于等于y的值,否则出错
nvl
NVL( string1, replace_with)
它的功能是如果string1为NULL,则NVL函数返回replace_with的值,否则返回string1的值
如果两个参数都为NULL ,则返回NULL。
相当于java 的 switch case 或者if else
案例
悟空 A 男
娜娜 A 男
宋宋 B 男
凤姐 A 女
热巴 B 女
慧慧 B 女
A 2 1
B 1 2
vi emp_sex.txt
create table emp_sex(
name string,
dept_id string,
sex string
)
row format delimited fields terminated by "\t";
load data local inpath '/opt/module/datas/emp_sex.txt' into table emp_sex;
select
dept_id,
sum(case sex when '男' then 1 else 0 end) as male_count,
sum(case sex when '女' then 1 else 0 end) as female_count
from
emp_sex
group by
dept_id;
孙悟空 白羊座 A
娜娜 射手座 A
宋宋 白羊座 B
猪八戒 白羊座 A
凤姐 射手座 A
射手座,A 娜娜|凤姐
白羊座,A 孙悟空|猪八戒
白羊座,B 宋宋
create table person_info(
name string,
constellation string,
blood_type string
)
row format delimited fields terminated by "\t";
load data local inpath “/opt/module/datas/person_info.txt” into table person_info;
# 注意hql中一旦使用括号括起来,就需要使用别名,否则会出错
select
t1.base,
concat_ws('|', collect_set(t1.name)) as name
from
(select
name,
concat(constellation, ",", blood_type) as base
from
person_info) as t1
group by
t1.base;
《疑犯追踪》 悬疑,动作,科幻,剧情
《Lie to me》 悬疑,警匪,动作,心理,剧情
《战狼2》 战争,动作,灾难
《疑犯追踪》 悬疑
《疑犯追踪》 动作
《疑犯追踪》 科幻
《疑犯追踪》 剧情
《Lie to me》 悬疑
《Lie to me》 警匪
《Lie to me》 动作
《Lie to me》 心理
《Lie to me》 剧情
《战狼2》 战争
《战狼2》 动作
《战狼2》 灾难
create table movie(
name string,
category array<string>
)
row format delimited fields terminated by "\t"
collection items terminated by ",";
load data local inpath "/opt/module/datas/movie.txt" into table movie_info;
select
movie,
category_name
from
movie_info lateral view explode(category) table_tmp as category_name;
当分组聚合之后,还想操作集合之前的数据,就需要使用窗口函数。
- CURRENT ROW:当前行 current row
- n PRECEDING:往前n行数据 n preceding
- n FOLLOWING:往后n行数据 n following
- UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING表示到后面的终点 unbound preceding unbound following
- LAG(col,n):往前第n行数据 lag 参数一 字段 n
- LEAD(col,n):往后第n行数据 lead
- NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。 ntile(5)
Divides an ordered partition into x groups called buckets and assigns a bucket number to each row in the partition. This allows easy calculation of tertiles, quartiles, deciles, percentiles and other common summary statistics. (As of Hive 0.11.0.)
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)查询在2017年4月份购买过的顾客及总人数
(2)查询顾客的购买明细及月购买总额
(3)上述的场景,要将cost按照日期进行累加
(4)查询顾客上次的购买时间
(5)查询前20%时间的订单信息
create table business(
name string,
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath "/root/hive_sql/window4.txt" into table business;
select
name,
count(*) over ()
from
business
where substring(orderdate, 1, 7) = '2017-04'
group by name;
select
name,
orderdate,
cost,
sum(cost) over(partition by month(orderdate))
from
business;
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 business;
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 business;
select
*
from
(
select
* ,
ntile(5) over(order by orderdate ) as n
from
business
) as t
where t.n = 1;
孙悟空 语文 87
孙悟空 数学 95
孙悟空 英语 68
娜娜 语文 94
娜娜 数学 56
娜娜 英语 84
宋宋 语文 64
宋宋 数学 86
宋宋 英语 84
婷婷 语文 65
婷婷 数学 85
婷婷 英语 78
create table tb_score(
name string,
subject string,
score int
)
row format delimited fields terminated by '\t';
load data local inpath '/root/hive_sql/rank_src.txt' into table tb_score;
select
name,
subject,
score,
rank() over(partition by subject order by score desc) as rk,
dense_rank() over(partition by subject order by score desc) as dense_rk,
row_number() over(partition by subject order by score desc) as rn
from
tb_score;
从结果可以看出,只有row number是按照顺序往下计数,rank则排序相同时会减少一个序号,但总数不会改百年,dense rank则会总数都会减少
if(boolean testCondition, T valueTrue, T valueFalseOrNull)
就是hql中的判断语句,和case when很像,适合判断一个条件时
返回值: T
说明: 当条件testCondition为TRUE时,返回valueTrue;否则返回valueFalseOrNull
a,2017-02-05,200
a,2017-02-06,300
a,2017-02-07,200
a,2017-02-08,400
a,2017-02-10,600
b,2017-02-05,200
b,2017-02-06,300
b,2017-02-08,200
b,2017-02-09,400
b,2017-02-10,600
c,2017-01-31,200
c,2017-02-01,300
c,2017-02-02,200
c,2017-02-03,400
c,2017-02-10,600
a,2017-03-01,200
a,2017-03-02,300
a,2017-03-03,200
a,2017-03-04,400
a,2017-03-05,600
create table tb_shopping_log(
name string,
cday string,
cost int
)
row format delimited fields terminated by ',';
load data local inpath '/root/hive_sql/hive_window4.txt' into table tb_shopping_log;
select
name,
cday,
cost,
row_number() over(partition by name order by cday) as rn
from
tb_shopping_log;
select
name,
cday,
cost,
date_sub(cday, rn) as datesub
from
(select
name,
cday,
cost,
row_number() over(partition by name order by cday) as rn
from
tb_shopping_log) as t;
select
name,
count(1) as count
from
(select
name,
cday,
cost,
date_sub(cday, rn) as datesub
from
(select
name,
cday,
cost,
row_number() over(partition by name order by cday) as rn
from
tb_shopping_log) as t) as t2
group by datesub, name
having count > 3;