【MaxCompute学习】隐式转化的问题

有一次计算一个数据的百分比,想把小数结果取2位,并拼接一个百分号展示在结果报表中。用到的sql如下

select concat(round(10230/1497409,4)*100,'%') from  dual;

很奇怪局部数据并没有保留2位小数,比如上面的数据返回的是67.99999999999999

我计算了下上面的结果大概得到的数据为0.0068

select concat(round(0.0066 ,4)*100,'%') from  dual;--0.66%
select concat(round(0.0067 ,4)*100,'%') from  dual;--0.67%
select concat(round(0.0068 ,4)*100,'%') from  dual;--0.6799999999999999%
select concat(round(0.0069 ,4)*100,'%') from  dual;--0.69%

由于计算值采用了concat函数,concat的多个参数为string类型,如果输入为bigint,decimal,double,datetime类型会隐式转化为string类型,并且返回的为string类型

也就是说有两种情况

1.round函数返回的数字cast为string后就丢失了精度。 2.round函数返回的数字就丢失了精度。

select round(0.0066 ,4)*100 from dual; --0.66
select round(0.0067 ,4)*100 from dual; --0.67
select round(0.0068 ,4)*100 from dual; --0.6799999999999999
select round(0.0069 ,4)*100 from dual; --0.69

上面的结果说明是round函数返回的数字就丢失了精度。

round函数是用来计算指定到小数点位数的四舍五入的值的,如果其第一个参数为double类型,那么函数计算的结果就是double类型,如果其第一个参数为Decimal类型,那么函数计算的结果就是decimal类型的,如果其第一个参数为string类型或者bigint类型,那么就会隐式转化为double类型。

单独计算round的返回值如下,说明double类型的round返回值为double

select round(0.0068 ,4) from dual; --0.0068

再计算乘法的结果,double和bigint相计算的时候也是会发生隐式转化的

select 0.0066*100 from dual;--0.66
select 0.0067*100 from dual;--0.67
select 0.0068*100 from dual;--0.6799999999999999
select 0.0069*100 from dual;--0.69

对于操作符号的运算,string,bigint和double都可以参与算术运算,string类型会转成double类型计算 当bigint和bigint进行除法运算的时候结果会返回double类型,当bigint和double共同计算的时候,big今天会转成doule类型,并且返回结果为double类型,

那么100变成了double类型,这时候问题就有点眉目了

select cast(0.0068 as double) from dual;--0.0068
select cast(100 as double) from dual;--100.0
select 0.0068*100.0 from dual;--0.6799999999999999

double浮点数运算的时候会有丢失精度的问题,这个是所有的浮点数运算的通病,我们可以再java下验证一下

public class TestDouble {
    public static void main(String args[]){
        Double a=0.0068;
        Double b=100.0;

        System.out.println(a*b);//0.6799999999999999

        Double c=0.0067;
        Double d=100.0;

        System.out.println(c*d);//0.67

        BigDecimal e= new BigDecimal(0.0068);
        BigDecimal f=new BigDecimal(100.0);

        System.out.println(e.multiply(f));//0.679999999999999962113639284666533058043569326400756835937500

        BigDecimal g= new BigDecimal(Double.toString(0.0068));
        BigDecimal h=new BigDecimal(Double.toString(100.0));

        System.out.println(g.multiply(h));//0.68000
    }
}

当然这个问题的最终解决方案很简单,不过以后再计算对精度要求比较高的数据的时候建议还是设计成decimal类型

select round(10230*100/1497409,4) from  dual;

文章转载自wangming

更多问题欢迎加入MaxCompute钉钉群讨论

时间: 2024-11-30 00:50:28

【MaxCompute学习】隐式转化的问题的相关文章

MySQL隐式转化整理

前几天在微博上看到一篇文章:价值百万的 MySQL 的隐式类型转换感觉写的很不错,再加上自己之前也对MySQL的隐式转化这边并不是很清楚,所以就顺势整理了一下.希望对大家有所帮助. 当我们对不同类型的值进行比较的时候,为了使得这些数值「可比较」(也可以称为类型的兼容性),MySQL会做一些隐式转化(Implicit type conversion).比如下面的例子: mysql> SELECT 1+'1'; -> 2 mysql> SELECT CONCAT(2,' test'); -&

RDS SQL Server - 专题分享 - 巧用执行计划缓存之数据类型隐式转换

摘要 SQL Server数据库基表数据类型隐式转换,会导致Index Scan或者Clustered Index Scan的问题,这篇文章分享如何巧用执行计划缓存来发现数据类型隐式转换的查询语句,从而可以有针对性的优化查询,解决高CPU使用率的问题. 问题引入 测试环境 为了更好的展示从执行计划缓存缓存中找出导致数据类型转化的查询语句,我们先建立测试环境. -- Create testing database IF DB_ID('TestDb') IS NULL CREATE DATABASE

[20140116]视图?隐式转换?sql优化问题.txt

[20140116]视图?隐式转换?sql优化问题.txt 最近一直在优化单位的垃圾数据库,这个数据库可以讲是一个垃圾工程.在有优化的过程遇到视图中存在隐式转化问题,在我的测试环境模 拟出来,提出解决方案: 1.建立测试环境: SCOTT@test> @ver BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise

跟我学习javascript的隐式强制转换_javascript技巧

JavaScript的数据类型分为六种,分别为null,undefined,boolean,string,number,object. object是引用类型,其它的五种是基本类型或者是原始类型.我们可以用typeof方法打印来某个是属于哪个类型的.不同类型的变量比较要先转类型,叫做类型转换,类型转换也叫隐式转换.隐式转换通常发生在运算符加减乘除,等于,还有小于,大于等.. typeof '11' //string typeof(11) //number '11' < 4 //false 一.基

Android学习之Intent中显示意图和隐式意图的用法实例分析_Android

本文实例讲述了Android学习之Intent中显示意图和隐式意图的用法.分享给大家供大家参考,具体如下: Intent(意图)主要是解决Android应用的各项组件之间的通讯. Intent负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用. 因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦. 例如,在一个联系人

【PL/SQL 学习】隐式游标学习

--oracle 会为每一个非显示游标的sql dml 语句都创建一个隐式游标,隐式游标也称为sql 游标.与显示游标不同,不能对一个隐式游标执行open,close和fetch语句.oracle 隐式的打开sql游标,处理sql游标,然后再关闭该游标. declare   vid t.object_id%type;   vowner t.owner%type;  begin    select object_id ,owner into vid,vowner from t where rown

《Servlet和JSP学习指南》一3.3 隐式对象

3.3 隐式对象 Servlet容器将几个对象传给它所运行的Servlet.例如,在Servlet的service方法中获得HttpServletRequest和HttpServletResponse,并在init方法中获得ServletConfig.此外,还可以通过在HttpServletRequest对象中调用getSession获得一个HttpSession. 在JSP中,可以通过使用隐式对象来获取那些对象.表3-1列出了隐式对象. 例如,隐式对象request表示由Servlet/JSP

JavaScript运算符规则与隐式类型转换详解

本文中涉及的参考资料全部声明在了JavaScript 数据结构学习与实践资料索引 . 隐式类型转换 在 JavaScript 中,当我们进行比较操作或者加减乘除四则运算操作时,常常会触发 JavaScript 的隐式类型转换机制;而这部分也往往是令人迷惑的地方.譬如浏览器中的 console.log 操作常常会将任何值都转化为字符串然后展示,而数学运算则会首先将值转化为数值类型(除了 Date 类型对象)然后进行操作. 我们首先来看几组典型的 JavaScript 中运算符操作结果,希望阅读完本

第3课 隐式转换

1)val array=Array(1,2,3,4,5); array.map(item => 2*item);map的作用是循环遍历array中的每一个元素,并把每个元素做为具体的值传给map中的做为参数的函数.map执行结果为Array[Int] =Array(2,4,6,8,10);函数的参数也是函数,item时匿名函数,这个也是高阶函数 2)高阶函数的返回值也可能是函数.高阶函数的参数是函数,这是高阶函数的2个层面.高阶函数可以自动推断出函数参数的类型.而且对只有一个参数的函数,可以省略