十一、Hive JOIN 连接查询

#新星杯·14天创作挑战营·第11期#

作者:IvanCodes
日期:2025年5月16日
专栏:Hive教程

数据分析江湖中,数据往往分散不同的“门派”(表)之中。要洞察数据间的深层联系,就需要JOIN这把利器,将相关联的数据串联起来。Hive SQL 提供了多种 JOIN语法,如同六脉神剑,各有精妙之处。掌握它们,能让你在数据整合游刃有余

思维导图

在这里插入图片描述
在这里插入图片描述

准备工作:创建示例表

为了演示各种 JOIN,我们先创建两张简单的表:employees (员工表) 和 departments (部门表)。

-- 员工表
CREATE TABLE employees (
emp_id INT,
emp_name STRING,
dept_id INT
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;

-- 部门表
CREATE TABLE departments (
dept_id INT,
dept_name STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;

-- 插入数据
INSERT INTO employees VALUES
(1, '张三', 101),
(2, '李四', 102),
(3, '王五', 101),
(4, '赵六', 103),
(5, '孙七', NULL);

INSERT INTO departments VALUES
(101, '技术部'),
(102, '市场部'),
(104, '行政部');

Hive JOIN 六大语法详解

1. INNER JOIN (内连接,或简写为 JOIN)

  • 核心思想:只返回两张表中连接条件匹配的行。如果某行在一张表找不到另一张表中与之匹配的行,则该行不会出现在结果中。
  • 通用语法
SELECT table1.col1, table1.col2, table2.col_other
FROM table1
INNER JOIN table2
ON table1.join_column = table2.join_column;
  • 代码示例:查询所有有明确部门归属的员工及其部门名称。
SELECT e.emp_name, d.dept_name
FROM employees e
INNER JOIN departments d
ON e.dept_id = d.dept_id;
  • 预期输出
张三    技术部
李四    市场部
王五    技术部

2. LEFT OUTER JOIN (左外连接,或简写为 LEFT JOIN)

  • 核心思想返回左表中所有的行,以及右表中与左表连接条件匹配的行。如果右表没有匹配的行,则右表列值显示为 NULL
  • 通用语法
SELECT table1.col1, table1.col2, table2.col_other
FROM table1
LEFT OUTER JOIN table2
ON table1.join_column = table2.join_column;
  • 代码示例:查询所有员工,并显示他们的部门名称(如果存在)。
SELECT e.emp_name, e.dept_id AS emp_dept_id, d.dept_name
FROM employees e
LEFT JOIN departments d
ON e.dept_id = d.dept_id;
  • 预期输出
张三    101     技术部
李四    102     市场部
王五    101     技术部
赵六    103     NULL
孙七    NULL    NULL

3. RIGHT OUTER JOIN (右外连接,或简写为 RIGHT JOIN)

  • 核心思想:与 LEFT JOIN 相反。返回右表所有的行,以及左表中与右表连接条件匹配的行。如果左表没有匹配的行,则左表列值显示为 NULL
  • 通用语法
SELECT table1.col1, table2.col_other1, table2.col_other2
FROM table1
RIGHT OUTER JOIN table2
ON table1.join_column = table2.join_column;
  • 代码示例:查询所有部门,并显示部门下的员工姓名(如果存在)。
SELECT e.emp_name, d.dept_name, d.dept_id AS dep_dept_id
FROM employees e
RIGHT JOIN departments d
ON e.dept_id = d.dept_id;
  • 预期输出
张三    技术部    101
李四    市场部    102
王五    技术部    101
NULL    行政部    104

4. FULL OUTER JOIN (全外连接,或简写为 FULL JOIN)

  • 核心思想返回左表和右表中所有的行。当某行在另一张表没有匹配时,该表对应列值显示为 NULL
  • 通用语法
SELECT table1.col1, table2.col_other
FROM table1
FULL OUTER JOIN table2
ON table1.join_column = table2.join_column;
  • 代码示例:查询所有员工和所有部门的完整信息。
SELECT e.emp_name, e.dept_id AS emp_dept_id, d.dept_name, d.dept_id AS dep_dept_id
FROM employees e
FULL JOIN departments d
ON e.dept_id = d.dept_id;
  • 预期输出
张三    101     技术部    101
李四    102     市场部    102
王五    101     技术部    101
赵六    103     NULL    NULL
孙七    NULL    NULL    NULL
NULL    NULL    行政部    104

5. LEFT SEMI JOIN (左半连接)

  • 核心思想:这是 Hive 特有的一种 JOIN。它只返回左表中那些在右表存在匹配记录的行。关键在于,结果集中不包含右表的任何列。它更像是一个存在性检查 (类似于 SQL 中的 EXISTS 子查询)。
  • 通用语法
SELECT table1.col1, table1.col2
FROM table1
LEFT SEMI JOIN table2
ON table1.join_column = table2.join_column;
  • 代码示例:查询所有在部门表中确实存在对应部门的员工信息。
SELECT e.emp_id, e.emp_name, e.dept_id
FROM employees e
LEFT SEMI JOIN departments d
ON e.dept_id = d.dept_id;
  • 预期输出
1       张三    101
2       李四    102
3       王五    101

6. CROSS JOIN (交叉连接,笛卡尔积)

  • 核心思想返回左表中的每一行与右表中的每一行所有可能组合。结果集的行数是左表行数乘以右表行数。通常不使用 ON 子句(或者使用 ON 1=1 这种恒为真的条件)。
  • 通用语法
SELECT table1.col1, table2.col_other
FROM table1
CROSS JOIN table2;
  • 代码示例:显示员工和部门的所有可能组合(通常在实际业务中要谨慎使用)。
SELECT e.emp_name, d.dept_name
FROM employees e
CROSS JOIN departments d;
  • 预期输出: (员工表5行 * 部门表3行 = 15行,部分示例)
张三    技术部
张三    市场部
张三    行政部
李四    技术部
李四    市场部
李四    行政部
...
  • 注意:CROSS JOIN 非常容易产生巨大的结果集,消耗大量资源,务必谨慎使用

练习题

假设我们有如上创建的 employeesdepartments 表。

  1. 找出所有在“技术部”工作的员工姓名。
  2. 列出所有部门的名称,以及该部门的员工数量(如果某部门没有员工,数量显示为0)。
  3. 找出所有没有分配到任何有效部门的员工姓名(即员工表中的dept_id在部门表中不存在,或者员工的dept_id为NULL)。
  4. 列出所有员工的姓名,以及他们所在部门的名称。对于没有部门的员工孙七,部门名称应显示为 “未分配”;对于部门ID存在但部门表中无对应名称的赵六,部门名称应显示为 “未知部门”。
  5. 使用 LEFT SEMI JOIN,找出所有部门ID为101的员工信息。
  6. 解释 INNER JOIN 和 LEFT OUTER JOIN 在处理不匹配数据时的主要区别。
  7. 如果 employees 表有100行,departments 表有5行,那么 CROSS JOIN 会产生多少行结果?
  8. 找出所有既有员工,其部门也在部门表中存在的员工姓名和部门名称。(提示:思考多种JOIN方式)
  9. 使用 FULL OUTER JOIN,然后筛选出只存在于员工表(在部门表无匹配)或只存在于部门表(在员工表无匹配)的记录。请描述如何筛选。
  10. 查询所有部门ID (dept_id),以及这些部门的名称。如果一个部门ID只存在于员工表中,也需要列出这个ID,但部门名称显示为NULL。

练习题答案

  1. 找出所有在“技术部”工作的员工姓名。
SELECT e.emp_name
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
WHERE d.dept_name = '技术部';
  1. 列出所有部门的名称,以及该部门的员工数量(如果某部门没有员工,数量显示为0)。
SELECT d.dept_name, COUNT(e.emp_id) AS employee_count
FROM departments d
LEFT JOIN employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_id, d.dept_name;
  1. 找出所有没有分配到任何有效部门的员工姓名(即员工表中的dept_id在部门表中不存在,或者员工的dept_id为NULL)。
SELECT e.emp_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id
WHERE d.dept_id IS NULL;
  1. 列出所有员工的姓名,以及他们所在部门的名称。对于没有部门的员工孙七,部门名称应显示为 “未分配”;对于部门ID存在但部门表中无对应名称的赵六,部门名称应显示为 “未知部门”。
SELECT
e.emp_name,
CASE
WHEN e.dept_id IS NULL THEN '未分配'
WHEN d.dept_name IS NULL THEN '未知部门'
ELSE d.dept_name
END AS department_status
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;
  1. 使用 LEFT SEMI JOIN,找出所有部门ID为101的员工信息。
SELECT e.emp_id, e.emp_name, e.dept_id
FROM employees e
LEFT SEMI JOIN departments d ON e.dept_id = d.dept_id AND e.dept_id = 101;
  1. 解释 INNER JOIN 和 LEFT OUTER JOIN 在处理不匹配数据时的主要区别。
    INNER JOIN 只保留两边表中都能通过连接条件找到匹配的行。如果左表的一行在右表中没有匹配,或者右表的一行在左表中没有匹配,这些行都会被丢弃。
    LEFT OUTER JOIN 会保留左表的所有行。如果左表的某行在右表中找到了匹配,则合并两边的列;如果在右表中找不到匹配,则右表对应的列将填充为NULL,但左表的行仍然会出现在结果中。

  2. 如果 employees 表有100行,departments 表有5行,那么 CROSS JOIN 会产生多少行结果?
    100 * 5 = 500 行。

  3. 找出所有既有员工,其部门也在部门表中存在的员工姓名和部门名称。(提示:思考多种JOIN方式)

SELECT e.emp_name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
  1. 使用 FULL OUTER JOIN,然后筛选出只存在于员工表(在部门表无匹配)或只存在于部门表(在员工表无匹配)的记录。请描述如何筛选。
    筛选条件是:当 employees.emp_id IS NULL (表示这条记录只在departments表中有) 或者 departments.dept_id IS NULL (表示这条记录只在employees表中有,且连接失败)。
SELECT e.emp_name, e.dept_id AS emp_dept_id, d.dept_name, d.dept_id AS dep_dept_id
FROM employees e
FULL OUTER JOIN departments d ON e.dept_id = d.dept_id
WHERE e.emp_id IS NULL OR d.dept_id IS NULL;
  1. 查询所有部门ID (dept_id),以及这些部门的名称。如果一个部门ID只存在于员工表中,也需要列出这个ID,但部门名称显示为NULL。
SELECT DISTINCT e.dept_id AS emp_dept_id_distinct, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;
### Hive Join 使用方法及示例 #### 一、Hive Join 基本概念 Hive 提供了 SQL 类似的查询语言来处理和分析大规模的数据集,支持多种数据连接操作(Join)。这些操作允许用户从多个表中获取相关数据。理解 Hive Join 的原理与机制对于高效地进行数据分析和处理至关重要[^1]。 #### 二、Hive Join 类型及其语法结构 Hive 中常见的 Join 类型有 INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN 和 FULL OUTER JOIN。每种类型的 Join 都有不同的作用范围: - **INNER JOIN**: 返回两个表中共有的记录。 ```sql SELECT a.*, b.* FROM table_a a INNER JOIN table_b b ON a.id = b.id; ``` - **LEFT OUTER JOIN (左外连接)**: 返回左边表中的所有记录,如果右边表中有匹配,则返回匹配的记录;如果没有匹配,则结果为 NULL。 ```sql SELECT a.*, b.* FROM table_a a LEFT OUTER JOIN table_b b ON a.id = b.id; ``` - **RIGHT OUTER JOIN (右外连接)**: 返回右边表中的所有记录,如果左边表中有匹配,则返回匹配的记录;如果没有匹配,则结果为 NULL。 ```sql SELECT a.*, b.* FROM table_a a RIGHT OUTER JOIN table_b b ON a.id = b.id; ``` - **FULL OUTER JOIN (全外连接)**: 只要其中一个表存在匹配,就返回行。当某一边没有匹配时,另一边的结果会填充NULL。 ```sql SELECT a.*, b.* FROM table_a a FULL OUTER JOIN table_b b ON a.id = b.id; ``` 除了上述标准 Join 外,还有特殊的 Map-side Join 或者称为 MapJoin,在某些情况下可以显著提高性能。MapJoin 将较小的一方加载到内存中完成整个过程而不需要 Reduce 过程,从而加快速度[^2]。 ```sql -- 启用 mapjoin 并指定小表作为map端缓存 SET hive.auto.convert.join=true; SELECT /*+ MAPJOIN(small_table) */ big_table.key, small_table.value FROM big_table JOIN small_table ON big_table.key = small_table.key; ``` #### 三、实际应用案例 假设有一个订单表 `orders` 和客户信息表 `customers`, 我们可以通过以下方式查询每个客户的总消费金额: ```sql SELECT c.customer_name, SUM(o.amount) FROM orders o JOIN customers c ON o.customer_id = c.customer_id GROUP BY c.customer_name; ``` 此查询首先通过 customer_id 字段将两张表格相连,接着计算每位顾客所下的订单总额并按姓名汇总显示出来[^3].
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值