今天是中秋节,早上七点就醒了,干啥呢,大一开学后空教室紧缺,还不趁着假期来学校等啥呢。顺便偷偷许个愿吧,希望在明年的这个时候,秋招不知道赶不赶得上,我希望拿几个国奖,蓝桥杯、中国大学生计算机设计大赛、挑战杯、软件杯... 。最大的愿望还是能够早点找到一份心仪的工作!!!不说了,开卷!
查询语句必然是 Hive 的重中之重,之前的 SQL 基础也不是那么牢固,尤其是高级的 SQL 语句,这里需要恶补一下。
每个关键字的顺序不能颠倒。
- SELECT [ALL | DISTINCT] 字段1, 字段2, ...
- FROM 表名
- [WHERE 条件]
- [GROUP BY 字段] --分组查询
- [HAVING 字段] --分组后过滤(group by 后只能用 having 不能再用 where)
- [ORDER BY 字段] --排序
- [CLUSTER BY col_list
- | [DISTRIBUTE BY col_list] [SORT BY col_list]
- ]
- [LIMIT 页数] --分页显示
创建文件 dept.txt、emp.txt、loc.txt。
dept.txt:
- 10 行政部 1700
- 20 财务部 1800
- 30 教学部 1900
- 40 销售部 1700
emp.txt:
- 7369 张三 研发 800.00 30
- 7499 李四 财务 1600.00 20
- 7521 王五 行政 1250.00 10
- 7566 赵六 销售 2975.00 40
- 7654 侯七 研发 1250.00 30
- 7698 马八 研发 2850.00 30
- 7782 金九 \N 2450.0 30
- 7788 银十 行政 3000.00 10
- 7839 小芳 销售 5000.00 40
- 7844 小明 销售 1500.00 40
- 7876 小李 行政 1100.00 10
- 7900 小元 讲师 950.00 30
- 7902 小海 行政 3000.00 10
- 7934 小红明 讲师 1300.00 30
loc.txt:
- 1700 北京
- 1800 上海
- 1900 深圳
dept:
- use default;
- -- 创建部门表 在hdfs生成目录: /user/hive/warehouse/dept
- create table if not exists dept(
- deptno int, --部门编号
- dname string, --部门名称
- loc int --部门位置
- )
- row format delimited fields terminated by '\t';
emp:
- -- 创建员工表 在hdfs生成目录: /user/hive/warehouse/emp
- create table if not exists emp(
- empno int, --员工编号
- ename string, --员工姓名
- job string, --员工岗位
- sal double, --员工工资
- deptno int --部门编号
- )
- row format delimited fields terminated by '\t';
location:
- create table location(
- loc int,
- loc_name string
- )
- row format delimited fields terminated by '\t';
- load data local inpath '/opt/module/hive-3.1.2/datas/dept.txt' into table dept;
-
- load data local inpath '/opt/module/hive-3.1.2/datas/emp.txt' into table emp;
-
- load data local inpath '/opt/module/hive-3.1.2/datas/loc.txt' into table location;
- -- 查询全表
- select * from emp;
- -- 查询指定字段
- select empno,ename from emp;
可以省去 as 。
- -- 列别名 as 或者 直接字段后跟 别名
- select empno as id,ename name from emp;
- -- 分页显示 limit(begin,len) begin从0开始算起 向下读取len行
- select * from emp limit 5;
- select * from emp limit 0,3;
这里只
- -- 关系运算符
- -- 查询部门id为30或20的员工信息
- select * from emp
- where deptno in (30,20);
- -- 比较运算符
- select * from emp where sal =3000;
- select * from emp where sal between 500 and 1000;
- select * from emp where job is null;
- -- 查询除了20部门和30部门以外的员工信息
-
- select * from emp where deptno not IN(30, 20);
like 可以用来进行 模糊匹配:
Rlike 是 Hive 对like的扩展,使它可以通过Java的正则表达式这个更强大的语言来指定匹配条件。
- -- 查找名字以A开头的员工信息
- select * from emp where ename LIKE ‘A%’; hive
-
- select * from emp where ename RLIKE ‘^A’;
GROUP BY语句通常会和聚合函数一起使用,按照一个或者多个列队结果进行分组,然后对每个组执行聚合操作。
注意:使用聚合函数必须使用 group by!
在 Hive 中,当你在查询语句中使用聚合函数(如sum())时,你需要使用group by子句来对数据进行分组。这是因为聚合函数会对每个组的数据进行操作,而不是对整个数据集进行操作。
- -- 计算没个部门的平均工资
- select t.deptno, avg(t.sal) from emp t group by t.deptno; --用时27s
-
- --计算每个部门中每个岗位的最高薪水
- select t.deptno,t.job,max(t.sal) from emp t group by t.deptno,t.job; --用时22s
如果我们要对分组后的结果进行条件过滤,这时候不能使用 where ,需要使用 having。
- -- 使用 where 对grou by的结果进行再次过滤
- select job,cnt from
- (select job,count(*) cnt from emp group by job)t1
- where cnt>=2;
-
- -- 上面的写法太复杂了 所以有了 having
- select job,count(*) cnt from emp having cnt>=2;
-
- -- 查询平均工资>1000的部门id
- select deptno,avg(sal) avg_sal from emp group by deptno having avg_sal > 1000;
返回两张表中满足关联条件的行,拼接成一张宽表(因为两张表横向合并,字段增加)
- -- 内连接 (返回两张表的所有能关联上(满足e.deptno = d.deptno)的行)
- -- 根据部门编号查询出员工的部门名称
- select e.empno,e.ename,d.dname from emp e join dept d on e.deptno = d.deptno;
把左表的全部行和右表进行拼接,右表如果不满足拼接条件,则拼接的部分补 NULL。
当执行左外连接时,Hive 会将左表的每一行与右表中满足关联条件的行进行匹配。如果右表中存在匹配的行,则返回左表和右表中匹配行的组合。如果右表中不存在匹配的行,则返回左表的行,右表的部分将用 NULL 值填充。
- -- 左外连接 (返回左表的全部行)
- select e.empno,e.ename,d.deptno from emp e left join dept d on e.deptno = d.deptno;
把右表的全部行和左表进行拼接,左表如果不满足拼接条件,则拼接的部分补 NULL。
- -- 右外连接 (返回右表的全部行)
- select e.empno,e.ename,d.deptno from emp e right join dept d on e.deptno = d.deptno;
返回左表和右表中所有的行,以及两者之间满足连接条件的匹配行。如果某一侧的表中没有匹配的行,则返回NULL值。
- -- 满外连接
- select e.empno,e.ename,d.deptno from emp e full join dept d on e.deptno = d.deptno;
大多数情况下,Hive会对每对join连接对象启动一个MapReduce任务。本例中会首先启动一个MapReduce job对表e和表d进行连接操作,然后会再启动一个MapReduce job将第一个MapReduce job的输出和表l进行连接操作。
- -- 用emp表的deptno 关联dept表的deptno字段,再用dept表的loc字段关联location表的loc字段
- select * from emp e
- join dept d
- on e.deptno = d.deptno
- join location l
- on d.loc = l.loc;
4.6、笛卡尔集- --笛卡尔集 (把a表每一行数据和b表每一行数据关联到一起) 不要轻易使用
- -- a | 1 => (a,1)(b,1)(c,1)
- -- b | 2 => (a,2)(b,2)(c,2)
- -- c | 3 => (a,3)(b,3)(c,3)
- -- 结果总行数: a行数*b行数, 3*3=9行
- select empno,dname from emp,dept;
纵向拼接,要求必须字段数相同,字段类型相同。
- -- 联合union
- -- join 是横向拼接(形成宽表,增加了字段) 而 union是纵向拼接(增加表的数据,也就是两张表的大部分字段的个数和类型必须一致)
- -- union去重,union all不去重
- select * from emp
- where deptno = 30
- union
- select * from emp
- where deptno = 20;
语法:
select * from 表名 order by 字段 [asc | desc];
asc:升序(默认)
desc:降序
- -- 1.全局排序 order by
- -- asc: 升序 desc:降序
- select * from emp order by sal;
我们在实际开发中,order by 其实是一个比较危险的操作,因为我们一个 order by 操作的底层中,Map 可能是多个 Map 任务,但是 Reduce 任务默认只有一个。这样的话,如果我们这张表对应的数据源非常大,那么 Reduce 任务的压力可想而知。
实际开发中,我们更多的时候并不需要整个结果排好序的数据,而往往要的是前几个或者后几个数据,所以我们的 order by 经常是配合 limit 来使用的。这样的性能往往是最好的,因为假如有100w条数据,我们只需要前100个升序的结果,那么我们就可以让 Reduce 任务只拉取每个 Map 任务的前 100 条数据即可。
select * form 表名 order by 字段 limit 100;
作用:指定排序字段。
对于很大规模的数据,order by 可以保证所有的数据结果保存在一个文件并全局有序,但是很多时候,我们并不需要全局排序,此时可以使用 sort by。
sort by 为每个 Reduce 任务产生一个排序文件,只能保证每个 Reduce 任务的结果有序,而不是全局有序。
- -- 设置reduce 任务数量为 3
- set mapreduce.job.reduces = 3;
set mapreduce.job.reduces;
- -- 根据员工薪资进行降序排序
- select * from emp sort by sal desc ;
运行结果:

我们的数据并不是全局有序,而是分为了3块(reduce 任务个数),各自局部有序。
这里,我在 reduce 任务数为 3 的情况下又测试了一遍 order by,发现结果是全局有序了,说明有两个 reduce 任务没有开启。
- -- 格式化导出
- insert overwrite local directory '/opt/module/hive-3.1.2/datas/sortby-result'
- row format delimited fields terminated by '\t'
- select * from emp sort by sal;
运行结果:
可以看到,一共导出了3个文件,分别内部有序。
作用:指定分区字段
我们 hadoop 默认的分区规则如下:
- public int getPartition(K key, V value, int numReduceTasks) {
- return (key.hashCode() & 2147483647) % numReduceTasks;
- }
这里,我们指定我们的 Reduce 任务数为 3,这样理论应该产生 3 个分区:
- insert overwrite local directory '/opt/module/hive-3.1.2/datas/distributeby-result'
- row format delimited fields terminated by '\t'
- select * from emp distribute by sal;
运行结果:

如果我们的分区字段(distribute by)和排序字段(sort by)是同一个字段的时候,我们可以简写为 cluster by 。但是排序只能是升序排序,不能指定排序规则为ASC或者DESC。
select * from emp cluster by deptno;
相当于
- select * from emp
- sort by deptno
- distribute by deptno;