十一、Hive JOIN 连接查询

简介: 在 Hive 的世界里,JOIN 就像是数据间的红线,把原本分散在各自表里的信息串联起来。无论是内连接、外连接,还是 Hive 特有的左半连接,都各有“武功招式”,适用于不同场景。

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

思维导图

image.png

image.png

准备工作:创建示例表

为了演示各种 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 = '技术部';
    
  2. 列出所有部门的名称,以及该部门的员工数量(如果某部门没有员工,数量显示为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;
    
  3. 找出所有没有分配到任何有效部门的员工姓名(即员工表中的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;
    
  4. 列出所有员工的姓名,以及他们所在部门的名称。对于没有部门的员工孙七,部门名称应显示为 "未分配";对于部门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;
    
  5. 使用 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;
    
  6. 解释 INNER JOIN 和 LEFT OUTER JOIN 在处理不匹配数据时的主要区别。
    INNER JOIN 只保留两边表中都能通过连接条件找到匹配的行。如果左表的一行在右表中没有匹配,或者右表的一行在左表中没有匹配,这些行都会被丢弃。
    LEFT OUTER JOIN 会保留左表的所有行。如果左表的某行在右表中找到了匹配,则合并两边的列;如果在右表中找不到匹配,则右表对应的列将填充为NULL,但左表的行仍然会出现在结果中。

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

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

    SELECT e.emp_name, d.dept_name
    FROM employees e
    INNER JOIN departments d ON e.dept_id = d.dept_id;
    
  9. 使用 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;
    
  10. 查询所有部门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;
    
目录
相关文章
|
4天前
|
数据采集 人工智能 安全
|
13天前
|
云安全 监控 安全
|
5天前
|
自然语言处理 API
万相 Wan2.6 全新升级发布!人人都能当导演的时代来了
通义万相2.6全新升级,支持文生图、图生视频、文生视频,打造电影级创作体验。智能分镜、角色扮演、音画同步,让创意一键成片,大众也能轻松制作高质量短视频。
1102 152
|
18天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
1778 9
|
10天前
|
人工智能 自然语言处理 API
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸
一句话生成拓扑图!next-ai-draw-io 结合 AI 与 Draw.io,通过自然语言秒出架构图,支持私有部署、免费大模型接口,彻底解放生产力,绘图效率直接爆炸。
708 152
|
12天前
|
人工智能 安全 前端开发
AgentScope Java v1.0 发布,让 Java 开发者轻松构建企业级 Agentic 应用
AgentScope 重磅发布 Java 版本,拥抱企业开发主流技术栈。
664 14
|
7天前
|
SQL 自然语言处理 调度
Agent Skills 的一次工程实践
**本文采用 Agent Skills 实现整体智能体**,开发框架采用 AgentScope,模型使用 **qwen3-max**。Agent Skills 是 Anthropic 新推出的一种有别于mcp server的一种开发方式,用于为 AI **引入可共享的专业技能**。经验封装到**可发现、可复用的能力单元**中,每个技能以文件夹形式存在,包含特定任务的指导性说明(SKILL.md 文件)、脚本代码和资源等 。大模型可以根据需要动态加载这些技能,从而扩展自身的功能。目前不少国内外的一些框架也开始支持此种的开发方式,详细介绍如下。
467 5