SQLite 浮点问题

SQLite floating point issue

这个查询 returns 1.7763568394002505e-15 当它应该 return 0.00:

SELECT st.id
, Sum(
    CASE sa.Type 
    WHEN 4 THEN sa.quantity * (st.price - st.commission)
    WHEN 5 THEN -sa.quantity * (st.price - st.commission)
    ELSE 0.0 END
) Sales
FROM sales sa
JOIN stock st
  ON sa.stockid = st.id
WHERE st.id = 1
GROUP BY st.id

http://sqlfiddle.com/#!5/cccd8/3

这看起来像是典型的浮点计算问题,但我该如何解决? 我已尝试将各个列转换为 REAL,但没有任何区别。

您可以使用此查询模拟结果:

SELECT 26.3 - 10.52 - 15.78 AS Result

SQLite 的 REAL 不适合货币。 SQlite 不支持 SQL 小数或 SQL 数字数据类型,因此最好的选择是使用整数,并将值存储为分。

CREATE TABLE stock (
  id INTEGER,
  -- Store price and commission as integers, implying that price is in cents,
  -- (.20 is stored as 320) and commission is a two-digit percentage (0.57%
  -- is stored as 57).  This is how scaled integers work in general.
  price integer,
  commission integer,
  PRIMARY KEY(id)
);

CREATE TABLE sales (
  id INTEGER,
  stockid INTEGER,
  type INTEGER,
  quantity  INTEGER,
  PRIMARY KEY(id)
);

insert into stock values (1, 320, 57);
insert into sales values (1, 1, 4, 10);
insert into sales values (2, 1, 5, 4);
insert into sales values (3, 1, 5, 6);

这个查询,来自你的 SQLfiddle,正确 returns 0。

SELECT st.id
, Sum(
    CASE sa.Type 
    WHEN 4 THEN sa.Quantity * (st.price - st.commission)
    WHEN 5 THEN -sa.Quantity * (st.price - st.commission)
    ELSE 0.0 END
) Sales
FROM sales sa
JOIN stock st
  ON sa.stockid = st.id
WHERE st.id = 1
GROUP BY st.id;
id          Sales
----------  ----------
1           0

转换为更合适的数据类型(不是 为 REAL)将隐藏 一些问题——甚至可能是大多数问题,甚至是所有问题他们在一个特定的应用程序。但是转换不会解决它们,因为存储的值可能与您真正想要的值不同。

Mike Sherrill 是正确的,您可能应该使用整数。但是为了快速修复,您可以将 Sum 调用包装在 Round(__,2) 中以四舍五入到最接近的美分。