MySQL科学计数法展示解惑

MySQL科学计数法展示解惑:数据库中的科学计数法展示 总结起来,MySQL数据库中的科学计数法是一种常见的展示大数或小数的方式。在MySQL中,科学计数法使用E(或e)作为指数的表示符号,E之前的数字是尾数,E之后的数字表示指数。例如,1.23E+10表示1.23乘以10的10次方,而1.23E-10表示1.23乘以10的负10次方。在上面的代码中,我们创建了一个名为"example"的表,其中包含一个名为"value"的DECIMAL类型的列。如果你想在查询结果中禁用科学计数法,可以使用FORMAT函数来手动格式化数据的展示。如果你有任何疑问,请随时提问。 阅读详情
  • GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。
  • GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。
  • 作者: 好好先生

一、问题引入

今天遇到一个很奇怪的问题,在MySQL客户端输入,用不同科学计数法表示的数值,展示效果却截然不同:

mysql> select 1e+14,1e+15;
+-----------------+-------+
| 1e+14           | 1e+15 |
+-----------------+-------+
| 100000000000000 |  1e15 |
+-----------------+-------+

为什么都是用科学计数法,一个是用完全展开的形式表示,另外一个却变成用科学计数法来表示?

二、代码跟踪

我们知道,在MySQL中解析这类科学计数法的标识token,是通过BISON来进行词法和语法解析的,并最终转成Item类型,Item构造初始化的堆栈如下所示:

#0  Item_float::init (this=0x7fffe844e8c0, str_arg=0xe7f312c00e0f8 <error: Cannot access memory at address 0xe7f312c00e0f8>, length=21845) at /home/greatdb/sql/item.cc:7216
#1  0x0000555559260095 in Item_float::Item_float (this=0x7fff2c00dad8, pos=..., str_arg=0x7fff2c00dac8 "1.234e-14", length=9) at /home/greatdb/sql/item.h:5237
#2  0x00005555592503af in MYSQLparse (YYTHD=0x7fff2c001040, parse_tree=0x7fffe84506b0) at /home/greatdb/sql/sql_yacc.yy:16616
#3  0x0000555558ea2410 in THD::sql_parser (this=0x7fff2c001040) at /home/greatdb/sql/sql_class.cc:3149
#4  0x0000555558fe8126 in parse_sql (thd=0x7fff2c001040, parser_state=0x7fffe8450990, creation_ctx=0x0) at /home/greatdb/sql/sql_parse.cc:7391
#5  0x0000555558fe1f16 in dispatch_sql_command (thd=0x7fff2c001040, parser_state=0x7fffe8450990, update_userstat=false) at /home/greatdb/sql/sql_parse.cc:5293
#6  0x0000555558fd7969 in dispatch_command (thd=0x7fff2c001040, com_data=0x7fffe8451b70, command=COM_QUERY) at /home/greatdb/sql/sql_parse.cc:1994
#7  0x0000555558fd5cd9 in do_command (thd=0x7fff2c001040) at /home/greatdb/sql/sql_parse.cc:1442
#8  0x00005555591fffc6 in handle_connection (arg=0x555560992ff0) at /home/greatdb/sql/conn_handler/connection_handler_per_thread.cc:307
#9  0x000055555ae2314b in pfs_spawn_thread (arg=0x5555608507a0) at /home/greatdb/storage/perfschema/pfs.cc:2899
#10 0x00007ffff77c3609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#11 0x00007ffff76e8133 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

我们仔细看下面这个函数的实现:

void Item_float::init(const char *str_arg, uint length) {
  int error;
  const char *end_not_used;
  //经过观察,我们发现:不管是1e+14还是1e+15,这里把字符串转成浮点数,都是完全展开形式。
  //即1e+14展开为100000000000000
  //1e+15展开为1000000000000000
  //说明至少到目前为止,没有触发展示差异的原因。
  value = my_strntod(&my_charset_bin, str_arg, length, &end_not_used, &error);
  if (error) {
    char tmp[NAME_LEN + 1];
    snprintf(tmp, sizeof(tmp), "%.*s", length, str_arg);
    my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", tmp);
  }
  presentation.copy(str_arg, length);
  item_name.copy(str_arg, length);
  set_data_type(MYSQL_TYPE_DOUBLE);
  decimals = (uint8)nr_of_decimals(str_arg, str_arg + length);
  max_length = length;
  fixed = true;
}

接着我们继续查看Item处理结果的堆栈信息:

#0  my_gcvt (x=100000000000000, type=MY_GCVT_ARG_DOUBLE, width=342, to=0x7fffe844ec60 "\033", error=0x0) at /home/greatdb/strings/dtoa.cc:428
#1  0x00005555594ba4d5 in floating_point_to_text (value=100000000000000, decimals=31, gcvt_arg_type=MY_GCVT_ARG_DOUBLE, buffer=0x7fffe844ec60 "\033") at /home/greatdb/sql/protocol_classic.cc:3539
#2  0x00005555594ba53d in store_floating_point (value=100000000000000, decimals=31, zerofill=0, gcvt_arg_type=MY_GCVT_ARG_DOUBLE, packet=0x7fff2c003148) at /home/greatdb/sql/protocol_classic.cc:3558
#3  0x00005555594ba703 in Protocol_text::store_double (this=0x7fff2c005600, from=100000000000000, decimals=31, zerofill=0) at /home/greatdb/sql/protocol_classic.cc:3579
#4  0x0000555558aa2260 in Item::send (this=0x7fff2c021f90, protocol=0x7fff2c005600, buffer=0x7fffe844ef00) at /home/greatdb/sql/item.cc:7625
#5  0x0000555558ea1886 in THD::send_result_set_row (this=0x7fff2c001040, row_items=const mem_root_deque<Item*> & = {...}) at /home/greatdb/sql/sql_class.cc:2975
#6  0x0000555558ddbf7d in Query_result_send::send_data (this=0x7fff2c022c88, thd=0x7fff2c001040, items=const mem_root_deque<Item*> & = {...}) at /home/greatdb/sql/query_result.cc:109
#7  0x000055555912c6e3 in Query_expression::ExecuteIteratorQuery (this=0x7fff2c021408, thd=0x7fff2c001040) at /home/greatdb/sql/sql_union.cc:1282
#8  0x000055555912ca74 in Query_expression::execute (this=0x7fff2c021408, thd=0x7fff2c001040) at /home/greatdb/sql/sql_union.cc:1342
#9  0x0000555559069670 in Sql_cmd_dml::execute_inner (this=0x7fff2c022c50, thd=0x7fff2c001040) at /home/greatdb/sql/sql_select.cc:827
#10 0x00005555590689ec in Sql_cmd_dml::execute (this=0x7fff2c022c50, thd=0x7fff2c001040) at /home/greatdb/sql/sql_select.cc:580
#11 0x0000555558fe0324 in mysql_execute_command (thd=0x7fff2c001040, first_level=true) at /home/greatdb/sql/sql_parse.cc:4788
#12 0x0000555558fe24bb in dispatch_sql_command (thd=0x7fff2c001040, parser_state=0x7fffe8450990, update_userstat=false) at /home/greatdb/sql/sql_parse.cc:5393
#13 0x0000555558fd7969 in dispatch_command (thd=0x7fff2c001040, com_data=0x7fffe8451b70, command=COM_QUERY) at /home/greatdb/sql/sql_parse.cc:1994
#14 0x0000555558fd5cd9 in do_command (thd=0x7fff2c001040) at /home/greatdb/sql/sql_parse.cc:1442
#15 0x00005555591fffc6 in handle_connection (arg=0x555560992ff0) at /home/greatdb/sql/conn_handler/connection_handler_per_thread.cc:307
#16 0x000055555ae2314b in pfs_spawn_thread (arg=0x5555608507a0) at /home/greatdb/storage/perfschema/pfs.cc:2899
#17 0x00007ffff77c3609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#18 0x00007ffff76e8133 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

我们发现不管是1e+14还是1e+15,最终都会进入到my_gcvt这个函数里面,此函数大概的功能是把一个浮点数类型转成对应的字符串类型输出。现在我们来看该函数的关键逻辑实现:

//1、x表示要转换的浮点数
//2、width表示展示宽度。具体来说:MySQL其实对数据库返回的每一个列的最大宽度是有要求的。如果浮点数是完全展开的情况,那就有可能超过这个展示的最大宽度,这里固定取值342
//3、to表示存放转换后浮点数x对应的字符数组指针
size_t my_gcvt(double x, my_gcvt_arg_type type, int width, char *to,
               bool *error) {
  int decpt, sign, len, exp_len;
  char *res, *src, *end, *dst = to, *dend = dst + width;
  char buf[DTOA_BUFF_SIZE];
  bool have_space, force_e_format;
  assert(width > 0 && to != nullptr);
 ...
 //这里主要是为了计算浮点数x的存储的小数点位置decpt。
 //比如100000000000000,得到的decpt为15
 //1000000000000000,得到的decpt为16
  res =
      dtoa(x, 4, type == MY_GCVT_ARG_DOUBLE ? width : std::min(width, FLT_DIG),
           &decpt, &sign, &end, buf, sizeof(buf));
 ...
 //have_space为真表示,浮点数完全展开的形式对应的长度,符合MySQL列展示最大宽度的要求。
 //下面这个判断的逻辑主要是说:
 //浮点数的展示宽度足够或者展示宽度不足的情况下,继续判断小数点位置decpt是否介于[-MAX_DECPT_FOR_F_FORMAT + 1,MAX_DECPT_FOR_F_FORMAT]之间。
 //跟踪一下代码的宏定义,很容易发现MAX_DECPT_FOR_F_FORMAT定义的长度就是15。
 //那这样就是说decpt介于[-14,15]之间的时候,也是符合要求的。
  if ((have_space ||
       /*
         Not enough space, let's see if the 'f' format provides the most number
         of significant digits.
       */
       ((decpt <= width &&
         (decpt >= -1 || (decpt == -2 && (len > 1 || !force_e_format)))) &&
        !force_e_format)) &&

      /*
        Use the 'e' format in some cases even if we have enough space for the
        'f' one. See comment for MAX_DECPT_FOR_F_FORMAT.
      */
      (!have_space || (decpt >= -MAX_DECPT_FOR_F_FORMAT + 1 &&
                       (decpt <= MAX_DECPT_FOR_F_FORMAT || len > decpt)))) {
  //如果符合这个条件的要求,那浮点数x就按照'f' format,即非科学计数法,完全展开形式处理。
  //1e+14的decpt取值为15,介于[-14,15]区间,故按照完全展开形式处理。
  ...
 }else{
  //否则浮点数x按照'e' format,即科学计数法表示。
  //1e+15的decpt取值为16,超出[-14,15]区间,故按照科学计数法形式处理。
  ...
 }
}

三、总结

经过代码的调用分析,发现最终的结论和输入数据的现象相符。当我们在使用MySQL过程中,遇到问题的时候,不要慌乱。可以尝试从源码分析的角度作为切入点,从根源上理解这种现象触发的原因,更能进一步加深我们对数据库运行机制的了解和掌握。


Enjoy GreatSQL :)

关于 GreatSQL

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

捉虫活动详情:https://greatsql.cn/thread-97-1-1.html

社区博客有奖征稿详情:https://greatsql.cn/thread-100-1-1.html

6440

转换科学计数法的数值字符串为decimal类型的方法 今天小编就为大家分享一篇转换科学计数法的数值字符串为decimal类型的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 立即下载

相关推荐

TCP三次握手,四次挥手的全过程,为什么需要三次握手,四次挥手

文章目录TCP介绍三次握手四次挥手滑动窗口拥塞避免算法 TCP介绍 三次握手 四次挥手

热爱编程的菜鸟 1万+

mysql更新后变成科学记数,CONVERT函数解决

mysql更新后变成科学记数,CONVERT函数解决

jcmcom的博客 2824

利用NURBS曲线进行点云曲面拟合算法

点云拟合曲面算法是将点云数据拟合成一个二次或高次曲面模型的算法。这种算法主要用于三维模型重建、计算机视觉、机器人感知、医学图像处理等领域。最小二乘法(Least Squares Method):通过最小化点到曲面距离的平方和来拟合曲面模型。三角剖分算法(Triangulation-Based Method):将点云构建成三角网格,再拟合成曲面模型。隐式曲面算法(Implicit Surface Method):通过定义一个隐式函数来表示曲面,然后用点云数据来估计隐式函数的系数。

weixin_44770969的博客 1万+

mysql 处理科学计数法的字段

在MySQL中,CAST函数用于将一个表达式转换成指定的数据类型。通过CAST函数,我们可以方便地将一个数据转换成另一种数据类型,例如将字符串转换成数字,或者将科学计数法表示的数字转换成普通的数字格式。FORMAT函数用于对数字进行格式化,通常用于将数字转换成带有逗号分隔符的格式,或者调整小数点位数。

牛肉胡辣汤 2357

VMware 安装 Windows11

一、下载win11的镜像文件 可以在MSDN网站下载: MSDN系统库-致力于原版windows生态服务 二、创建虚拟机 1.双击打开VMware虚拟机,点击创建新的虚拟机 2.选择典型(推荐),然后点击下一步 3.在安装程序光盘映像文件下,点击浏览按钮,选择Windows 11ISO镜像文件所在的路径,在Windows 11安装文件路径中不要有中文或其他特殊符号,否则有可能引起错误。然后点击下一步 4.在选择客户机操作系统界...

m0_56015193的博客 7018

智能座舱架构与芯片- (9) 音频篇 上

从A2B收发器衍生出来的简化产品具备各种级别的功能,例如端点从节点(不支持TDM)、简化型主节点(支持较短的电缆和更少的从节点数量),以及简化型端点从节点(支持较短电缆和更少的PDM输入)。例如,AVB中的talker和listener是不同的设备,它们的参考时钟源可能并不相同。传统的车载收音机通过天线接收无线电信号,然后由调谐模块(Tuner)进行信号调谐,信道过滤,信道均衡,多路改善,信号解调等,转为数字信号后再交给DSP进行立体声解码,噪声抑制,弱信号处理,最后从车载音响系统进行播放。

joanna_xiao的博客 4907

sql查询将科学计数法转为数字型

忘了是哪来的数据,指标值value有科学计数法的情况,不方便做统计计算,所以就有了需要将科学计数法转为数字型的场景,sql查询如下: select convert(sum(volumes),decimal(16)) c_volumes from index_spiderdata_productions_sales_map ...

王世洪的博客 7150

MATLAB地理数据处理 25:植被物候提取及分析模型优化(Savitzky-Golay)

之前我写过一篇使用Savitzky-Golay处理遥感数据,获取地面物候信息的MATLAB代码,但是发现存在一些问题:对物候开始期和物候结束期的阈值设定都为相同值,但是有些研究中,需要根据不同的环境条件,设置不同的物候阈值,所以对其进行相应的修改。

amyniez的博客,欢迎交流讨论 2233

MySQL使用Navicat导出Excel时数字展示会变成科学计数法

问题描述:MySQL使用Navicat导出Excel时数字会变成科学计数法 解决方法:"数据" 类型需要在导出时转成 "字符串" 类型 select CONCAT(id,"\t") from test

北辰 2043

华为OD技术面八股文_C++_01

汇总华为OD技术面C++方向八股文真题,并提供详细解答。

qq_45776114的博客 1887

【GlobalMapper精品教程】027:路径剖面和和视线工具的使用

路径剖面视线工具允许您使用加载的高程数据集沿用户指定的路径获取垂直剖面。要定义生成3D路径剖面所遵循的路径,只需单击鼠标左键选择路径的点,然后石键单击以结束路径。出现一个带有剖面的对话框,允许您设置视线分析或优化端点。

智慧空间实验室 2049

[MySQL] 解决mysql导出excel数值型变成科学计数法问题

当有数据导出需求的时候 我们直接写sql语句就能实现 但是有时候mysql中存储的数值太大了,在excel里面会变成科学计数法,如果超过了64位的话,那么还会丢失精度 需要在sql语句中concat 拼接一个\t 例如这样的sql里的 concat('\t',a.ding_userid), select a.id, a.username, a.nickname, a.phone...

程序员老狼专注开发aigc或客服系统应用 1971

EMC基础知识总结

电磁干扰(Electromagnetic Interference),简称EMI,有和两种。传导干扰主要是电子设备产生的干扰信号通过导电介质或公共电源线互相产生干扰;辐射干扰是指电子设备产生的干扰信号通过空间耦合把干扰信号传给另一个电网络或电子设备。

学海无涯的专栏 1368

mysql 导出过长的数字列时变科学计数法问题解决办法

--mysql 导出数据时, 数字类型的列如果位数过长,变为科学计数法问题 concat('\t',a.IDCARD_NO) 例子: select concat('\t',a.IDCARD_NO) from 表a as a 转载于:https://www.cnblogs.com/yangjinwang/p/5833728.html...

weixin_30363509的博客 1019

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

mysql - DOUBLE转化为CHAR解决办法——cast 函数使用

昨天发现MYSQL数据类型如果是DOUBLE的,并且数据比较大的情况下,使用科学计数法输出数据,类似:3.155e+13的形式,可是前台不希望看到这样的结果,后台使用MYSQL的CAST函数解决了这个问题。 具体的语法如下:Cast(value astype) type不是都可以滴,可以转换的type如下: 二进制,同带binary前缀的效果 : BINARY字符型,可带...

aijia7039的博客 1084

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

mysql导出长数字格式化_MySQL导出xlsx文件源码 自动格式化会存在科学计数法的数字_新锐下载...

import pymysqlimport datetimeimport xlsxwriterdef Get_Conn_Config(Data_Key):"获取数据库配置信息"Data_Config = {"host": "","user": "","password": "","database": "",'port': 3306,'charset': 'utf8'}if Data_Key == ...

weixin_39828338的博客 134

java,mysql,oracle出现科学记数法问题

mysql出现科学记数法问题,使用concat(字段,'')解决; oracle使用to_char()解决; BigDecimal出现科学记数法问题,toString可以解决;

weixin_43872895的博客 1263

mysql 数字加法_MySQL中大数字加减,不产生千位符和科学计数

mysql数字加减科学计数法这两天因为需求,需要获取一张表的流水号。规则是这样的。当前日期+8位流水号。比如:2015062400000001,2015062400000002,2015062400000003....因为考虑到并发问题,所以解决的方案是:在MySQL写存储过程,逻辑如下:1、查询表今天流水号的最大主键值:如:SELECTMAX(a.ORDER_ID)fromZhang_Test...

weixin_36338813的博客 1519

mysql中查询出来的数据放哪_mysql将查询结果导出

一、首先确认当前数据库设置导出是允许的show variables like '%secure%';如果是null则代表不允许,这时可以用命令修改,或者直接修改数据库配置文件my.ini,在其中添加secure-file-priv=‘C:/var/Mysql/data’,最后记得要重启mysql服务select a.id,a.user_name,b.id,b.tran_id,b.money,b.s...

weixin_34851493的博客 343

mysql导出科学计数法问题

用mysql客户端工具导出数据到excel时,遇到长数值类型的字段往往会出现科学计数法,用如下小技巧可以完美解决: SELECT concat(registerNum,'\t') AS 考籍号 FROM t_score

Java架构技术分享 1456

mysql还原科学计数

从科学计数法还原MySQL数据 在MySQL数据库中,科学计数法是一种常见的数字表示方式。当处理大数字时,MySQL会使用科学计数法来表示,以节省存储空间。但在某些情况下,我们可能需要将科学计数法还原为普通数字格式,以便更好地理解数据。 什么是科学计数法? 科学计数法是一种用于表示非常大或非常小的数字的方法。它使用一个数字...

weixin_31328141的博客 334

小数型

– 浮点型 create table my_float( f1 float, f2 float(10,2) )charset utf8; – 精度大概在7为位左右 insert into my_float values (123.123,12345678.99); insert into my_float values (123.123,99999999.99); – ...

DOUBLEchen151的博客 725

python查询数据库数据并将数据写入csv文件,并读取

1、连接数据库 import mysql.connector #连接测试数据库 mydb = mysql.connector.connect( host="10.100.0.0", user="root", passwd="root", database="rongpia" ) #获取游标 mycursor=mydb.cursor() 2、执行sql语句 sql = "select status,red_status,order_id from cd_order

冬天来了的博客 3751

MySQL导出csv文件,数字过长出现科学计数法的问题

可以在需要处理的字段前面加【'】(MySQl会自动识别它为字符串),或者后面加【\t】(制表位)来解决

Java Punk 1万+

为什么DECIMAL(38,0)的取值范围是-1038+1到1038-1?

数据库中,Decimal数据类型,语法为:Decimal(P,S),P为精度,s为数字的小数位数,精度P的取值范围是:1到38, S的取值范围是0到P从而得出Decimal数据类型的取值范围是-1038+1到1038-1,请问这个取值范围是怎么得出的呀?谢谢啦! 问题出处:http://zhidao.baidu.com/question/202258324.html 尝试回答如...

Jzn18604719929的博客 1136
上一篇: MySQL 聚合函数初探
下一篇: 有趣的statement stack
GreatSQL社区
博客等级 码龄5年 1210粉丝 390原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值