当前位置: 首页 > news >正文

十一、Hive JOIN 连接查询

作者: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;

相关文章:

  • OpenCV 背景建模详解:从原理到实战
  • 【基础】Windows开发设置入门4:Windows、Python、Linux和Node.js包管理器的作用和区别(AI整理)
  • Spring Boot三层架构设计模式
  • 【设计模式】- 结构型模式
  • 从另一个视角理解TCP握手、挥手与可靠传输
  • UWB定位方案在水力发电站人员安全的应用推荐
  • Python字符串常用方法详解
  • 目标检测指标计算
  • 【MySQL】项目实践
  • 【Python 操作 MySQL 数据库】
  • SQL Server权限设置的几种方法
  • 排序算法之线性时间排序:计数排序,基数排序,桶排序详解
  • 游戏引擎学习第285天:“Traversables 的事务性占用”
  • Detected for tasks ‘compileDebugJavaWithJavac‘ (17) and ‘kspDebugKotlin‘ (21).
  • pytorch 15.1 学习率调度基本概念与手动实现方法
  • 以Linux内核为基础的 Linux发行版有哪些
  • 如何使用 4 种方法安全地将 Windows 7恢复出厂设置
  • LabVIEW图像粒子处理
  • ubuntu 20.04 更改国内镜像源-阿里源 确保可用
  • Word图片格式调整与转换工具
  • 新闻1+1丨强对流天气频繁组团来袭,该如何更好应对?
  • 终于,俄罗斯和乌克兰谈上了
  • 手机表面细菌菌落总数可能比马桶高10倍,医生详解如何洗手
  • 陕西榆林:全力推进榆林学院升格榆林大学
  • 不是10点!乌克兰官员称尚未就俄乌谈判开始时间达成一致
  • 俄方代表团抵达土耳其,俄乌直接谈判有望于当地时间上午重启