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

十四、Hive 视图 Lateral View

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

Hive中,我们经常需要不同于原始表结构的方式查看或处理数据。为了简化复杂查询提供数据抽象,以及处理复杂数据类型(如数组或Map),Hive 提供了视图 (View) 和 Lateral View 这样强大的机制

思维导图

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

一、Hive 视图 (View):数据的逻辑窗口

Hive 视图是一个虚拟表,它的内容由一个查询定义。视图本身不存储任何物理数据,而是在被查询时动态执行其定义SELECT语句,并返回结果

视图的优势:

  1. 简化复杂性:将多表连接、复杂函数、聚合封装在视图中,用户只需查询简单的视图。
  2. 数据抽象隐藏底层表物理细节。若底层表结构改变,只需修改视图定义,上层应用可能无需变动
  3. 访问控制:可以创建只暴露部分列或符合特定条件行的视图,增强数据安全性
  4. 逻辑重用相同的查询逻辑定义一次,多处使用,便于维护。

基本视图操作:

(1) 创建视图 (CREATE VIEW)

CREATE VIEW [IF NOT EXISTS] view_name
[(column_list)]
[COMMENT view_comment]
AS SELECT_statement;

示例: 假设有 employees (id, name, department_id, salary) 和 departments (id, name) 表。

CREATE VIEW employee_department_details_view
COMMENT 'Shows employee name, salary, and their department name'
AS
SELECT e.name AS employee_name, e.salary, d.name AS department_name
FROM employees e
JOIN departments d ON e.department_id = d.id;

(2) 查询视图

SELECT * FROM employee_department_details_view WHERE salary > 60000;

(3) 查看视图定义

SHOW CREATE TABLE employee_department_details_view;

(4) 修改视图 (ALTER VIEW)

ALTER VIEW [db_name.]view_name AS SELECT_statement;

格式:

ALTER VIEW employee_department_details_view AS
SELECT e.name AS emp_name, e.salary, d.name AS dept_name, e.id AS emp_id -- 修改了列名并增加了列
FROM employees e
JOIN departments d ON e.department_id = d.id;

(5) 删除视图 (DROP VIEW)

DROP VIEW [IF EXISTS] [db_name.]view_name;

格式:

DROP VIEW IF EXISTS employee_department_details_view;

二、Lateral View:行转列的魔法

有时,我们的Hive表中会包含数组 (ARRAY)映射 (MAP) 这样的复杂数据类型。如果我们希望将这些集合类型中的每个元素键值对 “展开” 成单独的行,以便进行更细致的分析,这时就需要Lateral View

Lateral View 通常与表生成函数 (UDTF, User-Defined Table-generating Function) 一起使用,最常用的 UDTF 就是 explode()explode() 函数可以接收一个数组或Map作为输入,并为数组中的每个元素Map中的每个键值对输出一行

Lateral View 的工作方式:
Lateral View首先将 UDTF 应用基表每一行。然后,它将UDTF的输出行原始的输入行进行连接 (join),形成新的虚拟表行

语法:

SELECT ...
FROM base_table
LATERAL VIEW udtf(expression) table_alias AS column_alias_1 [, column_alias_2, ...];
  • udtf(expression): 表生成函数及其参数,如 explode(array_column)explode(map_column)
  • table_alias: 为 Lateral View 生成的虚拟表指定的别名。
  • column_alias_1, ...: 为 UDTF 输出的列指定的别名。explode(array) 只输出一列,explode(map) 输出两列 (key, value)。

示例1:展开数组
假设有一个表 user_hobbies (user_id INT, hobbies ARRAY)。

-- 假设 user_hobbies 表数据:
-- 1, ['reading', 'hiking']
-- 2, ['coding', 'gaming', 'reading']SELECT user_id, single_hobby
FROM user_hobbies
LATERAL VIEW explode(hobbies) exploded_hobbies_table AS single_hobby;

查询结果将会是:

1, reading
1, hiking
2, coding
2, gaming
2, reading

示例2:展开Map
假设有一个表 product_attributes (product_id INT, attributes MAP<STRING, STRING>)。

-- 假设 product_attributes 表数据:
-- 101, {'color':'red', 'size':'M'}
-- 102, {'material':'cotton', 'brand':'XYZ'}SELECT product_id, attr_key, attr_value
FROM product_attributes
LATERAL VIEW explode(attributes) exploded_attributes_table AS attr_key, attr_value;

查询结果将会是:

101, color, red
101, size, M
102, material, cotton
102, brand, XYZ

三、在视图定义中使用 Lateral View

Lateral View强大之处在于它可以被包含视图的 AS SELECT 定义中。这样,我们就可以创建一个视图永久性地提供这种展开后的数据展现形式

示例:创建一个视图来展示每个用户的单个爱好

CREATE VIEW user_individual_hobbies_view AS
SELECT user_id, single_hobby
FROM user_hobbies
LATERAL VIEW explode(hobbies) exploded_hobbies_table AS single_hobby;-- 后续查询
SELECT * FROM user_individual_hobbies_view WHERE user_id = 1;

四、视图(含Lateral View)的特性与注意事项

  1. 非物化:Hive 视图(包括使用了 Lateral View 的视图)默认不存储实际数据。每次查询时,都会重新执行其定义,确保数据最新
  2. 只读性:通常不能通过视图对底层表进行 INSERT, UPDATE, DELETE 操作。
  3. 性能考量:复杂的视图定义,特别是涉及多个Lateral View深层嵌套时,可能会影响查询性能。需要关注底层表优化 (如分区、分桶)。
  4. ORDER BY 限制:视图定义中的 SELECT 不推荐直接使用 ORDER BY (除非配合 LIMIT)。排序应在最终查询视图时应用。

总结: Hive 视图提供了数据的逻辑抽象层,而 Lateral View 则是处理和转换数组、Map等复杂结构强大工具。将两者结合使用,可以极大地增强数据分析和展现灵活性与便捷性


练习题

背景数据表:

  • products (product_id INT, product_name STRING, category STRING, price DECIMAL(8,2), tags ARRAY)
  • sales (sale_id INT, product_id INT, sale_date STRING, quantity INT, customer_id INT, sale_details MAP<STRING, STRING>)
  • customers (customer_id INT, customer_name STRING, city STRING)

请根据以下表结构和数据自行插入一些样例数据用于测试。
例如:
products 表中一条数据: (1, 'Laptop X', 'Electronics', 1200.00, array('slim', 'powerful', '15-inch'))
sales 表中一条数据: (101, 1, '2023-01-15', 1, 201, map('channel','online', 'promo_code','SAVE10'))

题目:

  1. 创建一个视图 product_basic_info_view,显示所有产品的 product_id, product_name, 和 price
  2. 创建一个视图 product_tags_expanded_view,将 products 表中的 tags 数组展开,每行显示 product_id, product_name 和一个单独的 tag
  3. 创建一个视图 sales_details_expanded_view,将 sales 表中的 sale_details Map展开,每行显示 sale_id, product_id,以及Map中的 detail_keydetail_value
  4. 创建一个视图 electronics_product_tags_view,只显示类别 (category) 为 ‘Electronics’ 的产品的 product_name 和其展开后的每个 tag
  5. 创建一个视图 total_quantity_per_product_view,显示每个 product_name 的总销售数量 (total_quantity)。
  6. 基于第5题的 total_quantity_per_product_view,创建一个新视图 high_sales_products_view,只显示 total_quantity 大于10的产品。
  7. 修改第2题创建的 product_tags_expanded_view,使其额外显示产品的 category
  8. 查看 sales_details_expanded_view 的创建语句。
  9. 假设有一个视图 customer_purchase_channels_view,它通过展开 sales.sale_details (假设其中有 ‘channel’ key) 来显示每个客户 (customer_name) 的购买渠道。请写出创建这个视图的SQL语句 (需要连接 customerssales 表)。
  10. 删除视图 product_basic_info_view

答案

  1. 创建 product_basic_info_view:
CREATE VIEW product_basic_info_view AS
SELECT product_id, product_name, price
FROM products;
  1. 创建 product_tags_expanded_view:
CREATE VIEW product_tags_expanded_view AS
SELECT p.product_id, p.product_name, single_tag
FROM products p
LATERAL VIEW explode(p.tags) exploded_tags_table AS single_tag;
  1. 创建 sales_details_expanded_view:
CREATE VIEW sales_details_expanded_view AS
SELECT s.sale_id, s.product_id, detail_key, detail_value
FROM sales s
LATERAL VIEW explode(s.sale_details) exploded_details_table AS detail_key, detail_value;
  1. 创建 electronics_product_tags_view:
CREATE VIEW electronics_product_tags_view AS
SELECT p.product_name, single_tag
FROM products p
LATERAL VIEW explode(p.tags) exploded_tags_table AS single_tag
WHERE p.category = 'Electronics';
  1. 创建 total_quantity_per_product_view:
CREATE VIEW total_quantity_per_product_view AS
SELECT p.product_name, SUM(s.quantity) AS total_quantity
FROM sales s
JOIN products p ON s.product_id = p.product_id
GROUP BY p.product_name;
  1. 创建 high_sales_products_view:
CREATE VIEW high_sales_products_view AS
SELECT product_name, total_quantity
FROM total_quantity_per_product_view
WHERE total_quantity > 10;
  1. 修改 product_tags_expanded_view:
ALTER VIEW product_tags_expanded_view AS
SELECT p.product_id, p.product_name, p.category, single_tag
FROM products p
LATERAL VIEW explode(p.tags) exploded_tags_table AS single_tag;
  1. 查看 sales_details_expanded_view 的创建语句:
SHOW CREATE TABLE sales_details_expanded_view;
  1. 创建 customer_purchase_channels_view:
CREATE VIEW customer_purchase_channels_view AS
SELECT
c.customer_name,
details.detail_value AS purchase_channel
FROM
customers c
JOIN
sales s ON c.customer_id = s.customer_id
LATERAL VIEW explode(s.sale_details) details_table AS detail_key, detail_value
WHERE details.detail_key = 'channel';
  1. 删除 product_basic_info_view:
DROP VIEW IF EXISTS product_basic_info_view;

相关文章:

  • Linux 文件(3)
  • 算法第25天 | 491. 非递减子序列、46. 全排列、47. 全排列 II
  • C语言——函数递归与迭代
  • 【Java高阶面经:微服务篇】6.从机房到线程池:隔离机制如何成为高可用系统的“隐形护盾”?
  • 基于Android的XX校园交流APP
  • CSDN gitcode代码推送
  • Python数据可视化高级实战之一——绘制GE矩阵图
  • C#语法篇 :基类子类转换,成员变化情况
  • Web3 领域中的一些专业术语
  • Circle宣布Circle Payments Network主网上线
  • 云祺容灾备份系统公有云备份与恢复实操-华为云
  • 面向恶劣条件的道路交通目标检测----大创自用(当然你也可以在里面学到很多东西)
  • 代码随想录打卡|Day45 图论(孤岛的总面积 、沉没孤岛、水流问题、建造最大岛屿)
  • Linux问题排查-引起服务器带宽使用率高的内鬼
  • 架构的设计
  • APM32小系统键盘PCB原理图设计详解
  • C语言中的弱符号 __attribute__((weak)) 的使用方法
  • asp.net web form nlog的安装
  • ARM反汇编浅析
  • Webpack 分包策略详解及实现
  • 网站建设工作总结范文/百度指数查询手机版app