前言

        今天是中秋节,早上七点就醒了,干啥呢,大一开学后空教室紧缺,还不趁着假期来学校等啥呢。顺便偷偷许个愿吧,希望在明年的这个时候,秋招不知道赶不赶得上,我希望拿几个国奖,蓝桥杯、中国大学生计算机设计大赛、挑战杯、软件杯... 。最大的愿望还是能够早点找到一份心仪的工作!!!不说了,开卷!

Hive 查询语句

        查询语句必然是 Hive 的重中之重,之前的 SQL 基础也不是那么牢固,尤其是高级的 SQL 语句,这里需要恶补一下。

1、基本语法

每个关键字的顺序不能颠倒。

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 页数]    --分页显示

2、基本查询

2.1、数据准备(Select…From)

创建文件 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;

2.2、全表和特定列查询

-- 查询全表
select * from emp;
-- 查询指定字段
select empno,ename from emp;

2.3、列别名

可以省去 as 。

-- 列别名 as 或者 直接字段后跟 别名
select empno as id,ename name from emp;

  2.3、limit 分页显示

-- 分页显示 limit(begin,len) begin从0开始算起 向下读取len行
select * from emp limit 5;
select * from emp limit 0,3;

2.4、关系运算符(between、in、is Null)

这里只

-- 关系运算符
-- 查询部门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;

2.5、逻辑运算符(and、or、not)

-- 查询除了20部门和30部门以外的员工信息

select * from emp where deptno not IN(30, 20);

 2.6、like 和 Rlike

like 可以用来进行 模糊匹配:

  • % 代表零个或多个字符(任意个字符)。
  • _ 代表一个字符。

Rlike 是 Hive 对like的扩展,使它可以通过Java的正则表达式这个更强大的语言来指定匹配条件。

-- 查找名字以A开头的员工信息
select * from emp where ename LIKE ‘A%’; hive

select * from emp where ename RLIKE ‘^A’;

3、分组

3.1、group by

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

3.2、having

如果我们要对分组后的结果进行条件过滤,这时候不能使用 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;

4、Join 语句

4.1、内连接

返回两张表中满足关联条件的行,拼接成一张宽表(因为两张表横向合并,字段增加)

-- 内连接 (返回两张表的所有能关联上(满足e.deptno = d.deptno)的行)
-- 根据部门编号查询出员工的部门名称
select e.empno,e.ename,d.dname from emp e join dept d on e.deptno = d.deptno;

4.2、左外连接

把左表的全部行和右表进行拼接,右表如果不满足拼接条件,则拼接的部分补 NULL。

当执行左外连接时,Hive 会将左表的每一行与右表中满足关联条件的行进行匹配。如果右表中存在匹配的行,则返回左表和右表中匹配行的组合。如果右表中不存在匹配的行,则返回左表的行,右表的部分将用 NULL 值填充。

-- 左外连接 (返回左表的全部行)
select e.empno,e.ename,d.deptno from emp e left join dept d on e.deptno = d.deptno;

4.3、右外连接

把右表的全部行和左表进行拼接,左表如果不满足拼接条件,则拼接的部分补 NULL。

-- 右外连接 (返回右表的全部行)
select e.empno,e.ename,d.deptno from emp e right join dept d on e.deptno = d.deptno;

4.4、满外连接

返回左表和右表中所有的行,以及两者之间满足连接条件的匹配行。如果某一侧的表中没有匹配的行,则返回NULL值。

-- 满外连接
select e.empno,e.ename,d.deptno from emp e full join dept d on e.deptno = d.deptno;

4.5、多表连接

大多数情况下,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;

hive 大数据分页查询 hive分页查询语句_hive 大数据分页查询

4.6、笛卡尔集

笛卡尔集会在下面条件下产生
  1. 省略连接条件
  2. 连接条件无效
  3. 所有表中的所有行互相连接
--笛卡尔集 (把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;

4.7、联合(union、union all)

纵向拼接,要求必须字段数相同,字段类型相同。

-- 联合union
-- join 是横向拼接(形成宽表,增加了字段) 而 union是纵向拼接(增加表的数据,也就是两张表的大部分字段的个数和类型必须一致)
-- union去重,union all不去重
select * from emp
where deptno = 30
union
select * from emp
where deptno = 20;

5、排序

5.1、全局排序(Order By)

语法:

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;

5.2、每个Reducer内部排序(Sort By)

作用:指定排序字段。

        对于很大规模的数据,order by 可以保证所有的数据结果保存在一个文件并全局有序,但是很多时候,我们并不需要全局排序,此时可以使用 sort by。

        sort by 为每个 Reduce 任务产生一个排序文件,只能保证每个 Reduce 任务的结果有序,而不是全局有序。

设置 reduce 个数
-- 设置reduce 任务数量为 3
set mapreduce.job.reduces = 3;
查看 reduce 个数
set mapreduce.job.reduces;
测试
-- 根据员工薪资进行降序排序
select * from emp sort by sal desc ;

运行结果: 

hive 大数据分页查询 hive分页查询语句_hive 大数据分页查询_02

我们的数据并不是全局有序,而是分为了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;

 运行结果:

hive 大数据分页查询 hive分页查询语句_字段_03

可以看到,一共导出了3个文件,分别内部有序。

5.3、分区(Distribute By)

作用:指定分区字段

我们 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;

运行结果: 

hive 大数据分页查询 hive分页查询语句_hadoop_04

5.4、分区排序(Cluster By)

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

select * from emp cluster by deptno;

相当于

select * from emp
sort by deptno
distribute by deptno;