You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Liquibase <sql>标签与PostgreSQL Shell执行SQL结果不一致问题

Why Does Liquibase's <sql> Tag Return Different Floating-Point String Output vs. PostgreSQL Shell?

这问题挺有意思的——本质上不是SQL语句本身的问题,而是不同客户端/工具在将浮点数转换为字符串时采用了不同的格式化策略,才导致最终的concat结果出现差异。

核心原因拆解

PostgreSQL里的DOUBLE(也就是float8)是遵循IEEE 754标准的二进制浮点数,你用到的0.99其实没办法被二进制浮点数精确存储,底层实际存的是一个非常接近0.99的近似值(就是你看到的0.98999999999999999)。那为什么psql和Liquibase输出不一样?

  • PostgreSQL Shell(psql)的处理逻辑:psql作为交互式客户端,会优先考虑可读性。它在把浮点数转成字符串时,会自动检测这个近似值可以简化成人类易读的0.99,所以会做截断/四舍五入的美化处理,不会输出底层存储的精确二进制转换结果。
  • Liquibase的处理逻辑:Liquibase是通过JDBC驱动和PostgreSQL交互的。当执行concat('value=', value)时,JDBC驱动在处理浮点数到字符串的转换时,更偏向于精确性——它会直接输出底层存储的近似值的完整十进制展开,没有做psql那种友好的格式化。简单说就是,JDBC驱动输出的是浮点数的“真实存储值”,而psql给你展示的是“美化后的友好值”。

如何让Liquibase的结果和psql一致?

如果你希望在Liquibase中得到和psql一样的value=0.99,可以手动指定浮点数的格式化规则,推荐用to_char函数替代直接拼接:

UPDATE myTable SET test=concat('value=', to_char(value, 'FM999999999.99'));

这里to_char能精确控制输出格式:FM用来去掉多余的前导空格,.99指定保留两位小数,这样就能得到一致的、易读的字符串结果。

或者,如果你需要更通用的处理(比如保留有效数字但避免冗长的近似值),可以先用round函数对浮点数做四舍五入:

UPDATE myTable SET test=concat('value=', round(value, 2));

额外说明

这种差异既不是Liquibase的bug,也不是PostgreSQL的问题,完全是不同工具的设计目标不同导致的:psql面向人类用户,优先可读性;JDBC驱动面向程序,优先精确性。

内容的提问来源于stack exchange,提问作者Stephane Grenier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:07:15