2.SUBSTR函数深度解析

张开发
2026/4/21 14:22:03 15 分钟阅读

分享文章

2.SUBSTR函数深度解析
Hive SUBSTR 函数深度解析目录函数概述语法定义SUBSTR 与 SUBSTRING 的关系参数详解4.1 str原始字符串4.2 pos起始位置4.3 len截取长度索引机制深度剖析5.1 正数索引从左向右截取5.2 负数索引从右向左截取5.3 索引值为 0 的特殊行为5.4 索引超出范围的边界情况NULL 值与空字符串处理各大数据引擎中的 SUBSTR 行为对比与其他截取函数的对比与选择8.1 SUBSTR vs SUBSTRING_INDEX8.2 SUBSTR vs SPLIT8.3 SUBSTR vs REGEXP_EXTRACT8.4 决策速查表高级用法与实战案例9.1 结合 INSTR 动态定位截取9.2 日期字段的拆分提取9.3 敏感信息脱敏处理9.4 固定宽度文件的字段解析性能优化建议总结1. 函数概述SUBSTR是 Hive SQL 中用于字符串截取的核心函数之一能够从原始字符串中提取指定位置和长度的子串。该函数语法简洁、执行高效是数据清洗、字段拆分、格式转换等场景中不可或缺的工具。函数名称SUBSTR函数类型字符串函数 (String Functions)主要功能返回字符串从指定起始位置开始、特定长度的子串应用场景提取身份证号中的出生日期、隐藏手机号中间四位、解析日志中的时间戳前缀、处理固定格式编码如银行卡号、订单号在 Hive 中SUBSTR和SUBSTRING是完全等价的同义词二者在语法、行为和性能上没有任何区别。2. 语法定义-- 语法一指定起始位置截取到字符串末尾SUBSTR(str,pos)-- 语法二指定起始位置和长度SUBSTR(str,pos,len)参数数量2 个或 3 个参数返回值类型STRING官方定义返回字符串str从pos位置开始、长度为len的子字符串3. SUBSTR 与 SUBSTRING 的关系在 Hive 中SUBSTR和SUBSTRING是完全等价的同义词不存在任何功能或性能差异。这一设计沿袭了 Oracle 和 MySQL 的习惯——Oracle 主要使用SUBSTR而 SQL Server 主要使用SUBSTRINGHive 同时支持两者以兼容不同开发者的编码习惯。-- 以下四条语句的结果完全相同SELECTSUBSTR(Hello World,7,5);-- 结果: WorldSELECTSUBSTRING(Hello World,7,5);-- 结果: WorldSELECTSUBSTR(Hello World,7);-- 结果: WorldSELECTSUBSTRING(Hello World,7);-- 结果: World选择建议如果团队成员主要来自 Oracle 背景优先使用SUBSTR如果团队成员主要来自 SQL Server 背景优先使用SUBSTRING无论选择哪一个建议在项目内部保持一致性4. 参数详解4.1 str原始字符串类型STRING或可隐式转换为STRING的类型说明需要进行截取操作的原始字符串可以是字符串常量、表中的字符串类型字段或是其他函数返回的字符串值。如果传入非字符串类型如INT、TIMESTAMPHive 会先将其隐式转换为字符串。4.2 pos起始位置类型INT核心规则Hive 中的字符串索引从 1 开始计数1-based而非从 0 开始正数表示从字符串左侧开始向右数第pos个字符负数表示从字符串右侧末尾向左数第|pos|个字符值为 0会被当作1处理即从第一个字符开始截取4.3 len截取长度类型INT可选参数说明指定要提取的子字符串的字符数非字节数。SUBSTR按字符计数中文等多字节字符按 1 个字符计算不会出现乱码截断问题。省略行为如果不指定len则默认截取从pos位置到字符串末尾的所有字符超出处理如果len大于从pos到字符串末尾的实际字符数则只返回到末尾为止的实际字符不会报错非正数处理如果len小于或等于 0返回空字符串5. 索引机制深度剖析5.1 正数索引从左向右截取-- 从第1个字符开始截取SELECTSUBSTR(Hadoop,1);-- 结果: Hadoop-- 从第2个字符开始截取SELECTSUBSTR(Hadoop,2);-- 结果: adoop-- 从第2个字符开始截取3个字符SELECTSUBSTR(Hadoop,2,3);-- 结果: ado-- 从第4个字符开始截取2个字符SELECTSUBSTR(abcdef,4,2);-- 结果: de5.2 负数索引从右向左截取负数索引从字符串末尾开始计数-1表示最后一个字符-2表示倒数第二个字符以此类推。这一特性在处理尾号、后缀等场景中非常实用。-- 截取最后一个字符SELECTSUBSTR(Hadoop,-1);-- 结果: p-- 从倒数第3个字符开始截取到末尾SELECTSUBSTR(abcdef,-3);-- 结果: def-- 从倒数第5个字符开始截取3个字符SELECTSUBSTR(Hello World,-5,3);-- 结果: Wor-- 从倒数第2个字符开始截取2个字符SELECTSUBSTR(abcde,-2,2);-- 结果: de-- 截取文件扩展名SELECTSUBSTR(document.pdf,-3);-- 结果: pdf5.3 索引值为 0 的特殊行为当pos 0时Hive 会将其自动视为pos 1即从第一个字符开始截取。SELECTSUBSTR(Hello,0,3);-- 结果: Hel 等同于 pos15.4 索引超出范围的边界情况边界场景函数行为示例及结果pos大于字符串长度返回空字符串SUBSTR(Hi, 5)→pos绝对值大于字符串长度负数返回空字符串SUBSTR(Hi, -5)→len为 0 或负数返回空字符串SUBSTR(Hello, 2, 0)→len超过剩余字符数截取到字符串末尾为止SUBSTR(Hello, 3, 10)→llo6. NULL 值与空字符串处理输入场景函数行为示例str为NULL返回NULLSUBSTR(NULL, 1, 2)→NULLpos为NULL返回NULLSUBSTR(Hello, NULL)→NULLlen为NULL返回NULLSUBSTR(Hello, 1, NULL)→NULLstr为空字符串返回空字符串SUBSTR(, 1, 2)→最佳实践在使用SUBSTR之前建议对可能为NULL的字段使用COALESCE或NVL进行防护处理。-- 推荐写法防止因 NULL 导致整行结果丢失SELECTSUBSTR(COALESCE(remark,),1,10)ASshort_remarkFROMorders;7. 各大数据引擎中的 SUBSTR 行为对比SUBSTR在不同大数据引擎中的行为存在细微差异迁移代码时需特别注意引擎索引基数负数索引支持0 索引行为备注Hive1-based支持从末尾倒数视为 1与 MySQL 行为一致Spark SQL1-based支持从末尾倒数视为 1与 Hive 完全兼容Presto/Trino1-based支持从末尾倒数视为 1函数名为SUBSTR和SUBSTRINGMySQL1-based支持从末尾倒数视为 1Hive 的参考标准Oracle1-based不支持负数索引视为 1负数索引返回NULLPostgreSQL1-based支持从末尾倒数视为 1SUBSTRING为主要函数SQL Server1-based不支持负数索引视为 1负数索引会报错关键差异Oracle 和 SQL Server 的SUBSTR/SUBSTRING不支持负数索引如果代码需要跨平台迁移建议使用RIGHT函数或LENGTH动态计算位置来替代负数索引。8. 与其他截取函数的对比与选择8.1 SUBSTR vs SUBSTRING_INDEX对比维度SUBSTRSUBSTRING_INDEX截取依据固定的字符位置指定的分隔符语法SUBSTR(str, pos, len)SUBSTRING_INDEX(str, delim, count)适用场景固定宽度字段身份证、日期、截取尾号分隔符分隔的字段URL、邮箱、路径示例SUBSTR(2024-01-15, 1, 4)→2024SUBSTRING_INDEX(a,b,c, ,, 2)→a,b8.2 SUBSTR vs SPLIT对比维度SUBSTRSPLIT截取依据固定的字符位置分隔符拆分后取数组元素返回值STRINGSTRING取数组某个元素适用场景位置固定的截取结构化分隔数据的提取示例SUBSTR(13812345678, 1, 3)→138SPLIT(2024-01-15, -)[0]→2024性能高直接定位中需执行拆分和数组操作8.3 SUBSTR vs REGEXP_EXTRACT对比维度SUBSTRREGEXP_EXTRACT截取依据固定的字符位置正则表达式模式匹配语法SUBSTR(str, pos, len)REGEXP_EXTRACT(str, pattern, index)适用场景位置固定、格式规则的截取复杂模式提取如提取所有数字、匹配特定格式示例SUBSTR(ID:10086, 4)→10086REGEXP_EXTRACT(ID:10086, [0-9], 0)→10086性能高O(1) 时间复杂度低正则引擎开销大8.4 决策速查表场景描述推荐函数理由提取身份证号中的出生日期第7-14位SUBSTR固定位置性能最优提取邮箱中的域名 之后的内容SUBSTRINSTR动态定位性能优于正则提取手机号后四位SUBSTR负数索引语法简洁语义清晰解析 CSV 格式字符串的第三列SPLIT(str, ,)[2]分隔符明确代码直观从日志中提取 IP 地址REGEXP_EXTRACT格式多变正则灵活截取 URL 中的路径部分SUBSTRING_INDEX有明确分隔符且需截取多个层级9. 高级用法与实战案例9.1 结合 INSTR 动态定位截取INSTR函数返回子串首次出现的位置与SUBSTR结合可实现动态定位截取。-- 提取邮箱中的域名部分 之后、. 之前或之后全部SELECTemail,SUBSTR(email,INSTR(email,)1)ASdomainFROMuser_email;-- 提取 URL 中的协议部分:// 之前SELECTurl,SUBSTR(url,1,INSTR(url,://)-1)ASprotocolFROMweb_log;-- 提取文件路径中的文件名最后一个 / 之后SELECTfile_path,SUBSTR(file_path,INSTR(file_path,/,-1)1)ASfile_nameFROMfile_system;9.2 日期字段的拆分提取-- 从日期字符串 2024-01-15 中提取年月日SELECTdate_str,SUBSTR(date_str,1,4)ASyear,SUBSTR(date_str,6,2)ASmonth,SUBSTR(date_str,9,2)ASdayFROMdate_table;-- 从时间戳 2024-01-15 14:30:25 中提取小时SELECTtimestamp_str,SUBSTR(timestamp_str,12,2)AShourFROMlog_table;9.3 敏感信息脱敏处理-- 手机号脱敏显示前3位和后4位中间用 **** 代替SELECTmobile,CONCAT(SUBSTR(mobile,1,3),****,SUBSTR(mobile,-4))ASmasked_mobileFROMuser_info;-- 结果示例138****5678-- 身份证号脱敏显示前6位和后4位SELECTid_card,CONCAT(SUBSTR(id_card,1,6),********,SUBSTR(id_card,-4))ASmasked_idFROMuser_info;-- 姓名脱敏只显示姓氏名字用 * 代替SELECTfull_name,CONCAT(SUBSTR(full_name,1,1),REPEAT(*,CHAR_LENGTH(full_name)-1))ASmasked_nameFROMuser_info;-- 结果示例张**、李*9.4 固定宽度文件的字段解析固定宽度文件Fixed-Width File是数据交换中的常见格式每个字段有固定的字符宽度。-- 假设有一行固定宽度数据前10位是姓名接下来18位是身份证号再接下来11位是手机号-- 示例数据张三 11010119900301123413812345678SELECTraw_line,TRIM(SUBSTR(raw_line,1,10))ASname,-- 第1-10位TRIM(SUBSTR(raw_line,11,18))ASid_card,-- 第11-28位TRIM(SUBSTR(raw_line,29,11))ASmobile-- 第29-39位FROMfixed_width_table;10. 性能优化建议优先使用SUBSTR而非正则表达式对于固定位置的截取SUBSTR是 O(1) 操作正则表达式涉及引擎解析和回溯性能差距可达数十倍。避免在大表扫描中对分区字段使用SUBSTR-- 不推荐会导致分区裁剪失效SELECT*FROMlogsWHERESUBSTR(dt,1,4)2024;-- 推荐直接比较分区值SELECT*FROMlogsWHEREdt20240101ANDdt20250101;预先计算并物化常用截取结果如果频繁使用SUBSTR提取某个字段的固定部分可在 ETL 阶段新增列存储结果后续直接查询该列。使用RIGHT函数替代负数SUBSTR在需要截取末尾固定长度字符时RIGHT(str, n)比SUBSTR(str, -n)语义更清晰性能完全一致。-- 二者等价RIGHT 可读性更佳SELECTRIGHT(mobile,4)FROMuser_info;SELECTSUBSTR(mobile,-4)FROMuser_info;注意字符串索引从 1 开始的认知成本与 Java、Python 等语言从 0 开始索引的习惯不同Hive SQL 的SUBSTR索引从 1 开始。建议在代码中添加注释或使用LEFT/RIGHT函数减少歧义。11. 总结SUBSTR是 Hive 中字符串截取的基础函数索引从 1 开始计数支持负数索引从末尾倒数。该函数与SUBSTRING完全等价可按团队习惯选择使用。处理NULL值需谨慎建议使用COALESCE进行防护。在跨平台迁移时注意 Oracle 和 SQL Server 对负数索引的不兼容问题。对于固定位置的截取优先使用SUBSTR对于分隔符字段使用SPLIT或SUBSTRING_INDEX对于复杂模式使用REGEXP_EXTRACT。结合INSTR可实现动态定位截取极大扩展了SUBSTR的应用场景。

更多文章