❝
开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题,有需求都可以加群群内有各大数据库行业大咖,可以解决你的问题。加群请联系 liuaustin3 ,(共3400人左右 1 + 2 + 3 + 4 +5 + 6 + 7 + 8 +9)(1 2 3 4 5 6 7 8群已经爆满 9群 300+,开10群PolarDB专业学习群110+)
SQLite 也可以做复杂的查询,我不信--SQLite 五脏俱全系列 (4)
SQLite 备份我不会,Down机了怎么办 SQLite 五脏俱全系列 (3)
什么int类型里面能插入文字,还不能改字段类型--SQLite 五脏俱全系列 (2)
SQLite需要初始化参数,怎么调优-- SQLite 五脏俱全系列 (1)
SQLite 开发中的数据库开发规范 --如何提升业务系统性能避免基础BUG
今天的内容SQLite是一个网友的问题,如何控制数值计算的问题

Sqlite金额精度计算怎么弄
SQLite中处理数据精度时,是没有其他数据库的Decimal和Numeric类型的数值的类型来保证数据计算的准确性,这里SQLite只有 REAL 一个数据类型浮点数。
这里我们主要针对三个部分进行显示
1 数据的展示
2 数据的计算
3 数据的存储
go
SQLite version 3.46.0 2024-04-15 20:43:21
Enter ".help"for usage hints.
sqlite> CREATE TABLE ShippingLogs (
id INTEGER PRIMARY KEY,
route_name TEXT,
distance_km REAL, -- 运输距离
unit_price REAL -- 每公里单价
);
INSERT INTO ShippingLogs (route_name, distance_km, unit_price) VALUES
('北京-上海', 1214.8, 5.5),
('上海-杭州', 175.234, 4.25),
('广州-深圳', 138.0, 6.0),
('跨国物流', 12500.5567, 12.888);
sqlite>
sqlite>
sqlite> select * from shippinglogs;
1|北京-上海|1214.8|5.5
2|上海-杭州|175.234|4.25
3|广州-深圳|138.0|6.0
4|跨国物流|12500.5567|12.888
sqlite>
go
SELECT
route_name AS 线路,
-- 展现 3 位精度的距离
format("%.3f KM", distance_km) AS 格式化里程,
-- 展现 2 位精度的单价
format("%.2f", unit_price) AS 单价,
-- 计算总价并进行展示封装
format("¥%.2f", ROUND(distance_km * unit_price, 2)) AS 总运费
FROM ShippingLogs;
go
sqlite> SELECT
route_name AS 线路,
format('%.3f KM', distance_km) AS 格式化里程,
format('%.2f', unit_price) AS 单价,
format('¥%.2f', ROUND(distance_km * unit_price, 2)) AS 总运费
FROM ShippingLogs;
北京-上海|1214.800 KM|5.50|¥6681.40
上海-杭州|175.234 KM|4.25|¥744.74
广州-深圳|138.000 KM|6.00|¥828.00
跨国物流|12500.557 KM|12.89|¥161107.17
go
sqlite> INSERT INTO TestPrecision VALUES (1.234567890123456789);
sqlite>
sqlite>
sqlite> SELECT
val AS 原始输入,
format('%.20f', val) AS 存储后的底层值,
format('%.20f', (val * 10.0) / 10.0) AS 运算后的值
FROM TestPrecision; ...> ...> ...> ...>
1.23456789012346|1.23456789012345700000|1.23456789012345700000
sqlite>
上面我们展示怎么显示和输入数字,但是我们文中提到了SQLite只是提供了REAL类型的IEEE 754双精度浮点存储数据值,会产生浮点的误差,如1.234567890123456789被存储为 1.23456789012345700000。
所以,我们在明知SQLite不能处理高精度的数值计算的情况下,就要使用程序外部计算的方式来进行。
这里有两种方式我们来讲已将
1 外部程序计算法,下面我们以python为例
go
from decimal import Decimal, getcontext
# 设置全局精度(可选)
getcontext().prec = 28
# 从数据库获取数据
rows = cursor.execute("""
SELECT route_name, distance_km, unit_price FROM ShippingLogs
""").fetchall()
results = []
for row in rows:
name, distance, price = row
# 转换为 Decimal 进行计算
# 注意:从数据库取出的 float 需要先转为字符串,以避免引入浮点误差
total_cost = Decimal(str(distance)) * Decimal(str(price))
# 格式化最终结果
formatted_cost = f"¥{total_cost:.2f}"
results.append((name, formatted_cost))
# 现在 results 列表里的数据是精确的
JAVA 程序同样的方式处理,这样处理的好处是,程序是可以随意定制的,程序可以支持各种精度的数字的计算,整个业务逻辑都在同一个语言中处理,方便进行维护和调试。
这样操作就和SQLite没有关系了。
计算的问题在程序中解决了,剩下的就是数据存储的问题,这里我们掌握两个核心
1 精确计算后的数值,不要存储成REAL类型,要存储成TEXT类型也将数值存储成文本
2 不要一股脑的将数据存储到一个数值字段中,或者一个文字字段中,而是要存储成两个字段,我们举例。
go
sqlite>
sqlite> CREATE TABLE ShippingLogs_Split (
id INTEGER PRIMARY KEY,
route_name TEXT,
distance_km REAL, -- 距离仍可用 REAL
unit_price_int INTEGER, -- 单价整数部分
unit_price_frac INTEGER, -- 单价小数部分(2(x1...> (x1...> (x1...> (x1...> (x1...> 位)
total_price_int INTEGER, -- 总价整数部分
total_price_frac INTEGER -- 总价小数部分(2位)
);(x1...> (x1...> (x1...>
sqlite>
sqlite>
sqlite> INSERT INTO ShippingLogs_Split (
route_name,
distance_km,
unit_price_int,
unit_price_frac,
total_price_int,
total_price_frac
) VALUES
('北京-上海', 1214.8, 5, 50, 6681, 40),
('上海-杭州', 175.234, 4, 25, 744, 74),
('广州-䧸1...> (x1...> (x1...> (x1...> (x1...> (x1...> (x1...> ...> ...> ...> ·±圳', 138.0, 6, 0, 828, 0),
('跨国物流', 12500.5567, 12, 89, 161107, 17); ...>
sqlite>
sqlite> select * from shippinglogs_split;
1|北京-上海|1214.8|5|50|6681|40
2|上海-杭州|175.234|4|25|744|74
3|广州-深圳|138.0|6|0|828|0
4|跨国物流|12500.5567|12|89|161107|17
sqlite>
数值输入后,我们展示的时候可以这样做
go
sqlite>
sqlite>
sqlite> SELECT
route_name,
format('%d.%02d', total_price_int, total_price_frac) AS total_price
FROM ShippingLogs_Split; ...> ...> ...>
北京-上海|6681.40
上海-杭州|744.74
广州-深圳|828.00
跨国物流|161107.17
sqlite>
最后我们总结一下,SQLite使用中,不支持精确的浮点计算,和数字的存储,作为SQLite的使用者,我们要改变原有的使用方式
在程序中计算,将整数和小数分开存储,并存储成文本防止存储的时候丢失精度。
