查询

支持基本ql的相关语法。

官方文档 https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Select

基本查询格式

1
2
3
4
5
6
7
8
9
10
11
[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 [offset,] rows]

测试数据准备

创建员工表和部门表

dept

1
2
3
4
5
6
7

10 ACCOUNTING 1700
20 RESEARCH 1800
30 SALES 1900
40 OPERATIONS 1700


emp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7369	SMITH	CLERK	7902	1980-12-17	800.00		20
7499 ALLEN SALESMAN 7698 1981-2-20 1600.00 300.00 30
7521 WARD SALESMAN 7698 1981-2-22 1250.00 500.00 30
7566 JONES MANAGER 7839 1981-4-2 2975.00 20
7654 MARTIN SALESMAN 7698 1981-9-28 1250.00 1400.00 30
7698 BLAKE MANAGER 7839 1981-5-1 2850.00 30
7782 CLARK MANAGER 7839 1981-6-9 2450.00 10
7788 SCOTT ANALYST 7566 1987-4-19 3000.00 20
7839 KING PRESIDENT 1981-11-17 5000.00 10
7844 TURNER SALESMAN 7698 1981-9-8 1500.00 0.00 30
7876 ADAMS CLERK 7788 1987-5-23 1100.00 20
7900 JAMES CLERK 7698 1981-12-3 950.00 30
7902 FORD ANALYST 7566 1981-12-3 3000.00 20
7934 MILLER CLERK 7782 1982-1-23 1300.00 10

1
2
3
4
5
6
create table if not exists dept(
deptno int,
dname string,
loc int
)
row format delimited fields terminated by '\t';
1
2
3
4
5
6
7
8
9
10
11
create table if not exists emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
row format delimited fields terminated by '\t';

数据导入

1
2
3
load data local inpath  '/home/hadoop/data/dept' into table dept;
load data local inpath '/home/hadoop/data/emp' into table emp;

数据准备完成

基本操作

  1. 列别名

as

  1. 运算符
  • A%B A对B取余
  • A&B A和B按位与
  • A|B A和B按位或
  • A^B A和B按位异或
  • ~A A按位取反
  • A / B
  • A - B
  • A<=>B 如果A和B都为NULL返回true,如果一边为NULL返回false

查询的时候可以执行

select A / 3 as num from xx; 得到对应的计算结果

  1. 比较运算
  • A=B 基本数据类型 如果A等于B则返回TRUE,反之返回FALSE
  • A<=>B 基本数据类型 如果A和B都为NULL,则返回TRUE,如果一边为NULL,返回False
  • A<>B, 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>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是基于java的正则表达式,如果A与其匹配,则返回TRUE;反之返回FALSE。匹配使用的是JDK中的正则表达式接口实现的,因为正则也依据其中的规则。例如,正则表达式必须和整个字符串A相匹配,而不是只需与其字符串匹配。
1
2
3
4
5
6
7
8
9
10
11
select ename = 'SMITH' from emp limit 2; 


+--------+
| _c0 |
+--------+
| true |
| false |
+--------+


  1. where 操作
1
2
select * from emp where comm is not null and hiredate > '1981-2-22';

+————+————+———–+———-+—————+———-+———–+————-+
| emp.empno | emp.ename | emp.job | emp.mgr | emp.hiredate | emp.sal | emp.comm | emp.deptno |
+————+————+———–+———-+—————+———-+———–+————-+
| 7654 | MARTIN | SALESMAN | 7698 | 1981-9-28 | 1250.0 | 1400.0 | 30 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-9-8 | 1500.0 | 0.0 | 30 |
+————+————+———–+———-+—————+———-+———–+————-+

基本函数

  • count()
  • avg()
  • min()
  • sum()
  • avg()

支持sql的基本函数,同时也支持复杂的自定义函数,后面说明。

like Rlike 操作

like 表示基本的模糊查询;
Rlike 使用java正则表达式达到更加复杂的字符匹配。 R 代表的是 REGEXP

_ 表示一个匹配符,% 代表多个匹配符,和mysql的sql 是不一样的。

  1. like 操作
1
2
select * from  emp where ename like 'S_ITH';

+————+————+———-+———-+—————+———-+———–+————-+
| emp.empno | emp.ename | emp.job | emp.mgr | emp.hiredate | emp.sal | emp.comm | emp.deptno |
+————+————+———-+———-+—————+———-+———–+————-+

1
select * from  emp where job like  'SA%';

+————+————+———–+———-+—————+———-+———–+————-+
| emp.empno | emp.ename | emp.job | emp.mgr | emp.hiredate | emp.sal | emp.comm | emp.deptno |
+————+————+———–+———-+—————+———-+———–+————-+
| 7499 | ALLEN | SALESMAN | 7698 | 1981-2-20 | 1600.0 | 300.0 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-2-22 | 1250.0 | 500.0 | 30 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-9-28 | 1250.0 | 1400.0 | 30 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-9-8 | 1500.0 | 0.0 | 30 |
+————+————+———–+———-+—————+———-+———–+————-+

  1. Rike 操作
1
2
select * from emp where ename rlike '^W.+D$';

+————+————+———–+———-+—————+———-+———–+————-+
| emp.empno | emp.ename | emp.job | emp.mgr | emp.hiredate | emp.sal | emp.comm | emp.deptno |
+————+————+———–+———-+—————+———-+———–+————-+
| 7521 | WARD | SALESMAN | 7698 | 1981-2-22 | 1250.0 | 500.0 | 30 |
+————+————+———–+———-+—————+———-+———–+————-+

分组

  1. 计算部门的平均工资
1
2
select deptno as dno , avg(mgr) as mgr  from emp group by deptno;

+——+———+
| dno | mgr |
+——+———+
| 10 | 7810.5 |
| 20 | 7732.2 |
| 30 | 7721.5 |

分组后,可以加having语句进行过滤。

join 连接查询

基本使用

1
2
select * from emp e left join dept d on e.deptno = d.deptno;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+----------+----------+------------+--------+-------------+---------+---------+-----------+-----------+-------------+--------+
| e.empno | e.ename | e.job | e.mgr | e.hiredate | e.sal | e.comm | e.deptno | d.deptno | d.dname | d.loc |
+----------+----------+------------+--------+-------------+---------+---------+-----------+-----------+-------------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-2-20 | 1600.0 | 300.0 | 30 | 30 | SALES | 1900 |
| 7521 | WARD | SALESMAN | 7698 | 1981-2-22 | 1250.0 | 500.0 | 30 | 30 | SALES | 1900 |
| 7566 | JONES | MANAGER | 7839 | 1981-4-2 | 2975.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-9-28 | 1250.0 | 1400.0 | 30 | 30 | SALES | 1900 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-5-1 | 2850.0 | NULL | 30 | 30 | SALES | 1900 |
| 7782 | CLARK | MANAGER | 7839 | 1981-6-9 | 2450.0 | NULL | 10 | 10 | ACCOUNTING | 1700 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-4-19 | 3000.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.0 | NULL | 10 | 10 | ACCOUNTING | 1700 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-9-8 | 1500.0 | 0.0 | 30 | 30 | SALES | 1900 |
| 7876 | ADAMS | CLERK | 7788 | 1987-5-23 | 1100.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-3 | 950.0 | NULL | 30 | 30 | SALES | 1900 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-3 | 3000.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7934 | MILLER | CLERK | 7782 | 1982-1-23 | 1300.0 | NULL | 10 | 10 | ACCOUNTING | 1700 |
+----------+----------+------------+--------+-------------+---------+---------+-----------+-----------+-------------+--------+

连接语法

  • 内连接
    join

  • 左连接

left join

  • 右连接

rigth join

满外连接

full join

满外连接会返回where 的所有的记录值,如果某个值没有符合的数据就返回 null值

使用满连接会将数据都显示出来

1
2
select * from emp e full  join dept d on e.deptno = d.deptno; 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
+----------+----------+------------+--------+-------------+---------+---------+-----------+-----------+-------------+--------+
| e.empno | e.ename | e.job | e.mgr | e.hiredate | e.sal | e.comm | e.deptno | d.deptno | d.dname | d.loc |
+----------+----------+------------+--------+-------------+---------+---------+-----------+-----------+-------------+--------+
| 7934 | MILLER | CLERK | 7782 | 1982-1-23 | 1300.0 | NULL | 10 | 10 | ACCOUNTING | 1700 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.0 | NULL | 10 | 10 | ACCOUNTING | 1700 |
| 7782 | CLARK | MANAGER | 7839 | 1981-6-9 | 2450.0 | NULL | 10 | 10 | ACCOUNTING | 1700 |
| 7876 | ADAMS | CLERK | 7788 | 1987-5-23 | 1100.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-4-19 | 3000.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7566 | JONES | MANAGER | 7839 | 1981-4-2 | 2975.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-3 | 3000.0 | NULL | 20 | 20 | RESEARCH | 1800 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-9-8 | 1500.0 | 0.0 | 30 | 30 | SALES | 1900 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-5-1 | 2850.0 | NULL | 30 | 30 | SALES | 1900 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-9-28 | 1250.0 | 1400.0 | 30 | 30 | SALES | 1900 |
| 7521 | WARD | SALESMAN | 7698 | 1981-2-22 | 1250.0 | 500.0 | 30 | 30 | SALES | 1900 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-2-20 | 1600.0 | 300.0 | 30 | 30 | SALES | 1900 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-3 | 950.0 | NULL | 30 | 30 | SALES | 1900 |
| NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | 40 | OPERATIONS | 1700 |
| 8000 | smi | CLERK | 200 | 2021-01-01 | 10.0 | NULL | 100 | NULL | NULL | NULL |
+----------+----------+------------+--------+-------------+---------+---------+-----------+-----------+-------------+--------+

注意: 在多个表连接的时候,每个连接都会产生一个MR job,所有关联几个表需要启动几个mr job,不过如果多个表的连接键相同的话,只会启动同一个mr job程序。

排序操作

基本排序

order by xx [desc | asc ]

sort By 排序

order by 排序是全局排序,如果是多个分区 的数据,也是全部获取进行排序,而reduce job中的key 本身就是有序的,当不需要全局排序只需要分区有序的时候,
可以使用sort by 排序提高排序性能。

设置2个job

1
2
3

set mapreduce.job.reduces=2;

执行排序操作

1
select * from emp sort by deptno desc;

可以看到结果 呈 2个排序结果 100 -10 30 -10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+------------+------------+------------+----------+---------------+----------+-----------+-------------+
| emp.empno | emp.ename | emp.job | emp.mgr | emp.hiredate | emp.sal | emp.comm | emp.deptno |
+------------+------------+------------+----------+---------------+----------+-----------+-------------+
| 8000 | smi | CLERK | 200 | 2021-01-01 | 10.0 | NULL | 100 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-3 | 950.0 | NULL | 30 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-9-8 | 1500.0 | 0.0 | 30 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-2-20 | 1600.0 | 300.0 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-2-22 | 1250.0 | 500.0 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-4-2 | 2975.0 | NULL | 20 |
| 7876 | ADAMS | CLERK | 7788 | 1987-5-23 | 1100.0 | NULL | 20 |
| 7782 | CLARK | MANAGER | 7839 | 1981-6-9 | 2450.0 | NULL | 10 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.0 | NULL | 10 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-9-28 | 1250.0 | 1400.0 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-5-1 | 2850.0 | NULL | 30 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-4-19 | 3000.0 | NULL | 20 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-3 | 3000.0 | NULL | 20 |
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.0 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-1-23 | 1300.0 | NULL | 10 |
+------------+------------+------------+----------+---------------+----------+-----------+-------------+

将结果导出可更明显的看到

1
insert overwrite local directory '/home/hadoop/sortby-result' select * from emp sort by deptno desc;

生成2个文件.文件内有序;

分区 Distribute By

在sort by 操作的时候,并不能执行根据什么进行分区,而通过Distribute By 可以指定分区的键,和mr 中的martition 类似;

1
set mapreduce.job.reduces=5;
1
select * from emp distribute by job sort by mgr desc;

​ 观察结果,可以看到mgr 是在每个job上降序的。

注意一定要设置job的 reduces 数量才会有此效果

Cluster By

当distribute by 和sort by 是同一个字段的时候,可以直接使用cluster by

cluster by A = distribute by A sort by A asc;

注意:Cluster By 只能是升序,不能是降序。

1
2
select * from emp cluster by job;