# Hive数据查询详解 ## 一、数据准备 为了演示查询操作,这里需要预先创建三张表,并加载测试数据。 > 数据文件 emp.txt 和 dept.txt 可以从本仓库的[resources](https://github.com/heibaiying/BigData-Notes/tree/master/resources) 目录下载。 ### 1.1 员工表 ```sql -- 建表语句 CREATE TABLE emp( empno INT, -- 员工表编号 ename STRING, -- 员工姓名 job STRING, -- 职位类型 mgr INT, hiredate TIMESTAMP, --雇佣日期 sal DECIMAL(7,2), --工资 comm DECIMAL(7,2), deptno INT) --部门编号 ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"; --加载数据 LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp; ``` ### 1.2 部门表 ```sql -- 建表语句 CREATE TABLE dept( deptno INT, --部门编号 dname STRING, --部门名称 loc STRING --部门所在的城市 ) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"; --加载数据 LOAD DATA LOCAL INPATH "/usr/file/dept.txt" OVERWRITE INTO TABLE dept; ``` ### 1.3 分区表 这里需要额外创建一张分区表,主要是为了演示分区查询: ```sql CREATE EXTERNAL TABLE emp_ptn( empno INT, ename STRING, job STRING, mgr INT, hiredate TIMESTAMP, sal DECIMAL(7,2), comm DECIMAL(7,2) ) PARTITIONED BY (deptno INT) -- 按照部门编号进行分区 ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"; --加载数据 LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=20) LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=30) LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=40) LOAD DATA LOCAL INPATH "/usr/file/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=50) ``` ## 二、单表查询 ### 2.1 SELECT ```sql -- 查询表中全部数据 SELECT * FROM emp; ``` ### 2.2 WHERE ```sql -- 查询 10 号部门中员工编号大于 7782 的员工信息 SELECT * FROM emp WHERE empno > 7782 AND deptno = 10; ``` ### 2.3 DISTINCT Hive 支持使用 DISTINCT 关键字去重。 ```sql -- 查询所有工作类型 SELECT DISTINCT job FROM emp; ``` ### 2.4 分区查询 分区查询 (Partition Based Queries),可以指定某个分区或者分区范围。 ```sql -- 查询分区表中部门编号在[20,40]之间的员工 SELECT emp_ptn.* FROM emp_ptn WHERE emp_ptn.deptno >= 20 AND emp_ptn.deptno <= 40; ``` ### 2.5 LIMIT ```sql -- 查询薪资最高的 5 名员工 SELECT * FROM emp ORDER BY sal DESC LIMIT 5; ``` ### 2.6 GROUP BY Hive 支持使用 GROUP BY 进行分组聚合操作。 ```sql set hive.map.aggr=true; -- 查询各个部门薪酬综合 SELECT deptno,SUM(sal) FROM emp GROUP BY deptno; ``` `hive.map.aggr` 控制程序如何进行聚合。默认值为 false。如果设置为 true,Hive 会在 map 阶段就执行一次聚合。这可以提高聚合效率,但需要消耗更多内存。 ### 2.7 ORDER AND SORT 可以使用 ORDER BY 或者 Sort BY 对查询结果进行排序,排序字段可以是整型也可以是字符串:如果是整型,则按照大小排序;如果是字符串,则按照字典序排序。ORDER BY 和 SORT BY 的区别如下: + 使用 ORDER BY 时会有一个 Reducer 对全部查询结果进行排序,可以保证数据的全局有序性; + 使用 SORT BY 时只会在每个 Reducer 中进行排序,这可以保证每个 Reducer 的输出数据是有序的,但不能保证全局有序。 由于 ORDER BY 的时间可能很长,如果你设置了严格模式 (hive.mapred.mode = strict),则其后面必须再跟一个 `limit` 子句。 > 注 :hive.mapred.mode 默认值是 nonstrict ,也就是非严格模式。 ```sql -- 查询员工工资,结果按照部门升序,按照工资降序排列 SELECT empno, deptno, sal FROM emp ORDER BY deptno ASC, sal DESC; ``` ### 2.8 HAVING 可以使用 HAVING 对分组数据进行过滤。 ```sql -- 查询工资总和大于 9000 的所有部门 SELECT deptno,SUM(sal) FROM emp GROUP BY deptno HAVING SUM(sal)>9000; ``` ### 2.9 DISTRIBUTE BY 如果想要把具有相同 Key 值的数据分发到同一个 Reducer 进行处理,这可以使用 DISTRIBUTE BY 字句。需要注意的是,DISTRIBUTE BY 虽然能把具有相同 Key 值的数据分发到同一个 Reducer,但是不能保证数据在 Reducer 上是有序的。情况如下: 把以下 5 个数据发送到两个 Reducer 上进行处理: ```properties k1 k2 k4 k3 k1 ``` Reducer1 得到如下乱序数据: ```properties k1 k2 k1 ``` Reducer2 得到数据如下: ```properties k4 k3 ``` 如果想让 Reducer 上的数据是有序的,可以结合 `SORT BY` 使用 (示例如下),或者使用下面我们将要介绍的 CLUSTER BY。 ```sql -- 将数据按照部门分发到对应的 Reducer 上处理 SELECT empno, deptno, sal FROM emp DISTRIBUTE BY deptno SORT BY deptno ASC; ``` ### 2.10 CLUSTER BY 如果 `SORT BY` 和 `DISTRIBUTE BY` 指定的是相同字段,且 SORT BY 排序规则是 ASC,此时可以使用 `CLUSTER BY` 进行替换,同时 `CLUSTER BY` 可以保证数据在全局是有序的。 ```sql SELECT empno, deptno, sal FROM emp CLUSTER BY deptno ; ``` ## 三、多表联结查询 Hive 支持内连接,外连接,左外连接,右外连接,笛卡尔连接,这和传统数据库中的概念是一致的,可以参见下图。 需要特别强调:JOIN 语句的关联条件必须用 ON 指定,不能用 WHERE 指定,否则就会先做笛卡尔积,再过滤,这会导致你得不到预期的结果 (下面的演示会有说明)。