十一、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;
相关推荐
柒间5 小时前
Elasticsearch 常用操作命令整合 (cURL 版本)
大数据·数据库·elasticsearch
G皮T7 小时前
【Elasticsearch】映射:fielddata 详解
大数据·elasticsearch·搜索引擎·映射·搜索·mappings·fielddata
viperrrrrrrrrr78 小时前
大数据学习(132)-HIve数据分析
大数据·hive·学习
夜影风9 小时前
大数据清洗加工概述
大数据
余+1853816280010 小时前
短视频矩阵系统文案创作功能开发实践,定制化开发
大数据·人工智能
阿里云大数据AI技术13 小时前
一体系数据平台的进化:基于阿里云 EMR Serverless Spark的持续演进
大数据·spark·serverless
TDengine (老段)14 小时前
TDengine 开发指南—— UDF函数
java·大数据·数据库·物联网·数据分析·tdengine·涛思数据
Stanford_110614 小时前
关于大数据的基础知识(二)——国内大数据产业链分布结构
大数据·开发语言·物联网·微信小程序·微信公众平台·twitter·微信开放平台
G皮T16 小时前
【Elasticsearch】一个图书馆的案例解释 Elasticsearch
大数据·elasticsearch·搜索引擎·全文检索·kibana·索引·index