Spark 小数精度和小数位在铸造时似乎错误

iba*_*alf 5 scala apache-spark

阅读文档,Spark DataType BigDecimal( precision,scale) 意味着

  • 精度是总位数,
  • 比例是小数点后的位数。

所以当我将一个值转换为十进制时

scala> val sss = """select cast(1.7142857343 as decimal(9,8))"""
scala> spark.sql(sss).show
+----------------------------------+
|CAST(1.7142857343 AS DECIMAL(9,8))|
+----------------------------------+
|                        1.71428573|  // It has 8 decimal digits
+----------------------------------+
Run Code Online (Sandbox Code Playgroud)

但是当我将值转换为 10.0 以上时,我得到 NULL

scala> val sss = """select cast(12.345678901 as decimal(9,8))"""
scala> spark.sql(sss).show
+----------------------------+
|CAST(11.714 AS DECIMAL(9,8))|
+----------------------------+
|                        null|
+----------------------------+
Run Code Online (Sandbox Code Playgroud)

我预计结果是12.3456789,

  • 为什么它是NULL?
  • 为什么 Precision 没有被实施?

hag*_*wal 6

要转换小数,spark 会在内部验证提供的模式小数(9,8) 是否比 12.345678901 实际模式小数(11,9) 宽。如果是,则意味着可以将数字安全地转换为提供的模式,而不会丢失任何精度或范围。看一下 org.apache.spark.sql.types.DecimalType.isWiderThan()

但是,在上述情况下,decimal(11,9) 无法转换为decimal(9,8),因此它返回 null。

//MAX_PRECISION = 38
val sss = """select cast(12.345678901 as decimal(38,7))"""
spark.sql(sss1).show(10)
+-----------------------------------+
|CAST(12.345678901 AS DECIMAL(38,8))|
+-----------------------------------+
|                         12.3456789|
+-----------------------------------+
Run Code Online (Sandbox Code Playgroud)