关于decimal(p,s)数据类型相乘为null的问题说明

  其他常见问题
内容纲要

概要描述


Inceptor 中 DECIMAL(p,s) 有两个参数:

  • p 为类型的精度(precision):它规定了该 DECIMAL 类型总共可以有多少位(包括小数点前和小数点后的位)。Inceptor中精度最大不能超过38。
  • s 为类型的标度(scale):它规定了该 DECIMAL 类型小数点后面的位数。s 不能大于 p。(decimal列的s不支持负数, 但是可以通过round传入负scale来达到类似Oracle的效果,不过Inceptor中会认为结果是scale=0的一个数)
  • 如果数据无法按照指定的精度和标度表示,将被认为是 NULL值。

详细说明


1. 新建一张ORC普通表EMP_ORC

> create table test(v1 decimal(38,20), v2 decimal(38,20));
> insert into test select 1,2 from system.dual;
--执行结果为null,与实际不符
> select v1*v2 from test;   --null

2. 原理分析

两个decimal(p,s)数据类型相乘,Inceptor中首先根据输入的decimal(常量表达式根据实际数据的ps,其他根据列的ps)的Precision和Scale计算目标Precision和Scale。

操作 结果Precision 结果Scale
e1*e2 p1+p2+1 s1+s2 *

对于乘法运算,如果算出来的Precision和Scale超过38,只取到38. 即:

  • 如果Precision 超过38,Scale没有超过38,则目标类型为decimal(38,scale)
  • 如果Precision和Scale都超过38,则目标类型为decimal(38,38)

*以下面的例子为例,两个decimal(38,20)数据类型相乘,结果Precision=38+38+1=77,结果Scale=20+20=40,Precision和Scale都超过38,Inceptor会优先保证Scale,所以实际推断值为decimal(38,38),而12=2,无法存入decimal(38,38),认为超界报错,所以为null。**

解决方案


方案一:TDH6.0.2版本可以通过参数,在数据超界时报错通知

> set inceptor.strict.evaluate=true;   --默认是false,这是之前已经存在的开关
> set inceptor.decimal.null.check=true;   --默认是false,这个是控制Decimal报错的关键开关,但是需要上面的开关配合,否则报错会被吞掉

file

方案二:通过Floating scale来尽量保存结果的整数部分

短时间内我们只能用Floating scale来workaround,Floating Scale会尽量保存结果的整数部分,该参数默认为false,需要手动set。后续已安排开发计划(Support decimal without precision/scale like number type in oracle)

> set inceptor.floating.scale.decimal=true;

file

FAQ

inceptor.floating.scale.decimal 该参数开关打开之后 create table xx as select 语句和 with xx as 语句可能会不支持,报错 floating scale decimal is not supported, 解决方案是 要么在 select 语句里的对应列外面套上 cast(xx as decimal(p,s)). 或者直接单独语句建表,把对应列的定义显示的写出来 。 下面举个例子:

--问题复现:
drop table IF EXISTS t2;
create table t2(a decimal(38,25));
insert into t2 select 312.0217 from system.dual;
select a*0.476893*0.476893*0.476893 from t2; --NULL

SET inceptor.floating.scale.decimal =TRUE;
-- 下面的语句执行报错:java.sql.SQLException: COMPILE FAILED: Semantic error: [Error 11371] floating scale decimal is not supported. Column name: _c0, column type: decimal(48,-2147483648)
CREATE TABLE test0002 AS select a*0.476893*0.476893*0.476893 from t2;

--解决方案:
--方案一:
CREATE TABLE test0002 AS select CAST (a*0.476893*0.476893*0.476893 AS decimal(38,20))from t2;
SELECT * FROM test0002;

--方案二:
DROP TABLE IF EXISTS test0003;
CREATE TABLE test0003 (DT DECIMAL(38,20));
INSERT INTO test0003 select a*0.476893*0.476893*0.476893 from t2;
SELECT * FROM test0003;

这篇文章对您有帮助吗?

平均评分 0 / 5. 次数: 0

尚无评价,您可以第一个评哦!

非常抱歉,这篇文章对您没有帮助.

烦请您告诉我们您的建议与意见,以便我们改进,谢谢您。