PySpark读取Oracle NUMBER类型精度超限问题(无需显式Schema)
解决PySpark读取Oracle NUMBER字段精度超限问题
问题背景
使用PySpark通过JDBC读取Oracle表时,表中包含35位长度的NUMBER类型字段,Spark自动推断Schema时将其识别为decimal(38,10),执行show()时抛出java.lang.ArithmeticException: Decimal precision 45 exceeds max precision 38错误,且不想通过显式定义Schema解决。
可行解决方案
1. 允许Decimal精度损失
通过Spark配置项spark.sql.decimalOperations.allowPrecisionLoss开启精度损失允许,让Spark自动处理超过38位精度的decimal值,避免报错。
from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("OracleDecimalFix") \ .config("spark.sql.decimalOperations.allowPrecisionLoss", "true") \ .getOrCreate() # 后续读取逻辑不变 df_rdbms_data = spark.read.jdbc(url=source_jdbc_url, table=source_table_name, properties=source_properties) df_rdbms_data.printSchema() df_rdbms_data.show()
该方案适合可以接受轻微精度损失的场景,Spark会自动截断超出精度范围的部分。
2. 将NUMBER字段转为字符串读取
通过JDBC自定义查询,把Oracle的NUMBER字段转换为字符串类型读取,从根源避免decimal精度问题。
# 构造包含字段转换的查询语句,替换other_columns为表中其他字段 query = f"(SELECT CAST(add_digit_num AS VARCHAR2(40)) AS add_digit_num, other_columns FROM {source_table_name}) AS temp_table" df_rdbms_data = spark.read.jdbc(url=source_jdbc_url, table=query, properties=source_properties) df_rdbms_data.printSchema() # 此时add_digit_num为string类型 df_rdbms_data.show()
若后续需要数值运算,可在Spark中再将字符串转换为精度符合要求的decimal类型(确保实际值精度≤38)。
3. 调整Oracle JDBC映射规则
修改JDBC连接属性,禁止将Oracle NUMBER映射为BigDecimal,转而使用基础数值类型(注意:超大数值可能出现精度损失,需根据实际数据评估)。
source_properties = { "user": "your_username", "password": "your_password", "driver": "oracle.jdbc.driver.OracleDriver", "oracle.jdbc.mapNumberToBigDecimal": "false" } df_rdbms_data = spark.read.jdbc(url=source_jdbc_url, table=source_table_name, properties=source_properties)
内容的提问来源于stack exchange,提问作者BigD
相关产品推荐
相关产品推荐

