十一、Hive JOIN 连接查询

作者:IvanCodes

日期:2025年5月16日

专栏:Hive教程

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

思维导图


准备工作:创建示例表

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

sql 复制代码
-- 员工表
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)

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

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

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

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

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

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

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

5. LEFT SEMI JOIN (左半连接)

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

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

  • 核心思想:返回左表中的每一行与右表中的每一行的所有可能组合。结果集的行数是左表行数乘以右表行数。通常不使用 ON 子句(或者使用 ON 1=1 这种恒为真的条件)。
  • 通用语法
sql 复制代码
SELECT table1.col1, table2.col_other
FROM table1
CROSS JOIN table2;
  • 代码示例:显示员工和部门的所有可能组合(通常在实际业务中要谨慎使用)。
sql 复制代码
SELECT e.emp_name, d.dept_name
FROM employees e
CROSS JOIN departments d;
  • 预期输出: (员工表5行 * 部门表3行 = 15行,部分示例)
bash 复制代码
张三    技术部
张三    市场部
张三    行政部
李四    技术部
李四    市场部
李四    行政部
...
  • 注意: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. 找出所有在"技术部"工作的员工姓名。
sql 复制代码
SELECT e.emp_name
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
WHERE d.dept_name = '技术部';
  1. 列出所有部门的名称,以及该部门的员工数量(如果某部门没有员工,数量显示为0)。
sql 复制代码
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)。
sql 复制代码
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存在但部门表中无对应名称的赵六,部门名称应显示为 "未知部门"。
sql 复制代码
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的员工信息。
sql 复制代码
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方式)

sql 复制代码
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表中有,且连接失败)。
sql 复制代码
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。
sql 复制代码
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;
相关推荐
随缘而动,随遇而安2 小时前
第八十八篇 大数据中的递归算法:从俄罗斯套娃到分布式计算的奇妙之旅
大数据·数据结构·算法
GISer_Jing3 小时前
Git协作开发:feature分支、拉取最新并合并
大数据·git·elasticsearch
IT_10244 小时前
Spring Boot项目开发实战销售管理系统——系统设计!
大数据·spring boot·后端
一只鹿鹿鹿6 小时前
信息化项目验收,软件工程评审和检查表单
大数据·人工智能·后端·智慧城市·软件工程
聚铭网络6 小时前
案例精选 | 某省级税务局AI大数据日志审计中台应用实践
大数据·人工智能·web安全
Qdgr_8 小时前
价值实证:数字化转型标杆案例深度解析
大数据·数据库·人工智能
选择不变8 小时前
日线周线MACD指标使用图文教程,通达信指标
大数据·区块链·通达信指标公式·炒股技巧·短线指标·炒股指标
高山莫衣8 小时前
git rebase多次触发冲突
大数据·git·elasticsearch
链上Sniper9 小时前
智能合约状态快照技术:实现 EVM 状态的快速同步与回滚
java·大数据·linux·运维·web3·区块链·智能合约
wx_ywyy67989 小时前
推客系统小程序终极指南:从0到1构建自动裂变增长引擎,实现业绩10倍增长!
大数据·人工智能·短剧·短剧系统·推客系统·推客小程序·推客系统开发