Oracle 在使用触发器时会失去浮点精度

问题描述 投票:0回答:1

我使用触发器填充同一个表的其他两列中的

SDO_POINT_TYPE
SDO_GEOMETRY
列。
由于某种原因,与直接插入相比,触发器改变了浮点值精度。
我想知道是否有一种简单的方法可以避免失去精度。

DROP TABLE test;
CREATE TABLE test (LONGITUDE BINARY_DOUBLE, LATITUDE BINARY_DOUBLE, p SDO_point_type);

CREATE OR REPLACE TRIGGER TEST_TRIGGER 
BEFORE UPDATE OF LATITUDE, LONGITUDE ON TEST
FOR EACH ROW  
BEGIN
    :new.p := sdo_point_type(:new.LONGITUDE, :new.LATITUDE, NULL);
END;

INSERT INTO test(p) VALUES(NULL);
UPDATE test SET longitude=-14.19, latitude=48.33; -- use trigger

INSERT INTO test(p, longitude, latitude) VALUES(sdo_point_type(-14.19, 48.33, NULL), -14.19, 48.33); -- no trigger
SELECT CAST(latitude AS VARCHAR2(100)) AS lat, CAST(t.p.y AS VARCHAR2(100)) AS point_lat FROM test t;

-- LAT                      POINT_LAT
-- 4,8329999999999998E+001  48,329999999999998  -- with trigger
-- 4,8329999999999998E+001  48,33               -- without trigger
oracle triggers precision spatial
1个回答
0
投票

停止使用

BINARY_DOUBLE
并使用
NUMBER

来自 Oracle 数据类型文档

代码 数据类型 描述
2
NUMBER [ (p [, s]) ]
具有精度
p
和小数位数
s
的数字。精度
p
的范围可以从 1 到 38。小数位数
s
的范围可以从 -84 到 127。精度和小数位数都是十进制数字。
NUMBER
值需要 1 到 22 个字节。
101
BINARY_DOUBLE
64 位浮点数。该数据类型需要 8 个字节。

浮点数

[...]

二进制浮点数与

NUMBER
的不同之处在于 Oracle 数据库内部存储值的方式。值使用
NUMBER
的十进制精度存储。所有在
NUMBER
支持的范围和精度内的文字都完全按照
NUMBER
存储。因为文字是使用十进制精度(数字 0 到 9)表示的,所以文字被精确存储。二进制浮点数使用二进制精度(数字 0 和 1)存储。这种存储方案无法精确地使用十进制精度表示所有值。通常,将值从十进制精度转换为二进制精度时发生的错误在将值从二进制精度转换回十进制精度时会被撤消。字面上的 0.1 就是这样一个例子。

这意味着:

  • BINARY_DOUBLE
    存储数字的最接近的近似值。
  • NUMBER
    存储准确的数字(前提是该数字在精度和小数位数指定的范围内)。

48.33
不可能使用 IEEE 64 位浮点数精确存储,最接近的可能表示是
48.329999999999998
。您可以使用
 NUMBER
数据类型准确存储它。

因此,如果您想精确存储值,请使用精确的数据类型。

© www.soinside.com 2019 - 2024. All rights reserved.