Spark SQL中varchar/char类型字符串对比失效问题求助
Spark SQL CHAR/VARCHAR类型字符串对比失效问题及解决
问题描述
通过spark-submit在Scala应用中使用Spark SQL查询CSV文件,创建了包含CHAR/VARCHAR类型字段的part表:
CREATE TABLE part ( p_partkey bigint, p_name varchar(55), p_mfgr char(25), p_brand char(10), p_type varchar(25), p_size int, p_container char(10), p_retailprice double, p_comment varchar(23) ) USING CSV LOCATION 'part.tbl' OPTIONS(delimiter "|");
基础查询SELECT * FROM part;可正常返回数据,但执行SELECT * FROM part WHERE p_brand = 'Brand#12';时,明明存在对应记录却返回空结果。将p_brand改为STRING类型后查询正常,VARCHAR(10)类型同样无效。
环境信息:
- Spark 3.3.2
- openjdk 17.0.6
- Scala 2.12.15
- Ubuntu 22.04
原因分析
Spark SQL对CHAR/VARCHAR类型的处理逻辑导致了该问题:
- CHAR类型:会自动将存储的字符串补空格到定义的长度(比如CHAR(10)会把"Brand#12"补成"Brand#12 "),但CSV文件中的原始数据并没有这些空格,导致查询字面量"Brand#12"和实际存储的带空格字符串匹配失败。
- VARCHAR类型:虽然不会自动补空格,但Spark在CSV数据源下解析定长VARCHAR时,存在类型适配的隐性问题,导致实际存储的字符串和预期不一致,同样无法匹配。
解决方案
1. 改用STRING类型
直接将表结构中的CHAR/VARCHAR字段改为STRING类型,这是最省心的方案,避免定长字符类型的适配问题:
CREATE TABLE part ( p_partkey bigint, p_name string, p_mfgr string, p_brand string, p_type string, p_size int, p_container string, p_retailprice double, p_comment string ) USING CSV LOCATION 'part.tbl' OPTIONS(delimiter "|");
2. 处理空格后对比
如果必须保留CHAR/VARCHAR类型,可以通过以下方式处理:
- 使用
TRIM()函数去掉字段的首尾空格后再对比:SELECT * FROM part WHERE TRIM(p_brand) = 'Brand#12'; - 或者给查询字面量补全对应长度的空格(比如CHAR(10)需要补2个空格):
SELECT * FROM part WHERE p_brand = 'Brand#12 ';
内容的提问来源于stack exchange,提问作者G.M
相关产品推荐
相关产品推荐

