首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >数据不准确,数据丢失,SQLite怎么保证计算不丢数--SQLite 五脏俱全系列 (5)

数据不准确,数据丢失,SQLite怎么保证计算不丢数--SQLite 五脏俱全系列 (5)

作者头像
AustinDatabases
发布2026-05-12 10:44:48
发布2026-05-12 10:44:48
980
举报
文章被收录于专栏:AustinDatabasesAustinDatabases

今天的内容SQLite是一个网友的问题,如何控制数值计算的问题

Sqlite金额精度计算怎么弄

SQLite中处理数据精度时,是没有其他数据库的Decimal和Numeric类型的数值的类型来保证数据计算的准确性,这里SQLite只有 REAL 一个数据类型浮点数。

这里我们主要针对三个部分进行显示

1 数据的展示

2 数据的计算

3 数据的存储

代码语言:javascript
复制
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> 
代码语言:javascript
复制
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;
代码语言:javascript
复制
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

代码语言:javascript
复制
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为例

代码语言:javascript
复制
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 不要一股脑的将数据存储到一个数值字段中,或者一个文字字段中,而是要存储成两个字段,我们举例。

代码语言:javascript
复制
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> 

数值输入后,我们展示的时候可以这样做

代码语言:javascript
复制
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的使用者,我们要改变原有的使用方式

在程序中计算,将整数和小数分开存储,并存储成文本防止存储的时候丢失精度。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AustinDatabases 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档