如果要存储的数据可能导致数据丢失,DuckDB将抛出错误

后端开发 2026-07-10

在DuckDB将大数字插入到 REAL (FLOAT4) 字段时会悄无声息地导致数据丢失或舍入误差。我猜这也会发生在其他数据类型的取值超出范围时,但遇到 REAL 的例子很容易。例如,下面的代码片段尝试将值 30000001 存储到几个字段中,但值 30000000 被错误地存储在 REAL 字段中,且没有抛出错误。

import {DuckDBInstance} from "@duckdb/node-api";

(async () => {
  // CREATE A DUCKDB INSTANCE AND CONNECT TO IT
  const db_instance = await DuckDBInstance.create(":memory:");
  const connection = await db_instance.connect();

  // CREATE A TABLE WITH REAL, DOUBLE, AND INTEGER VALUES
  await connection.run(`
DROP TABLE IF EXISTS "my_data";
CREATE TABLE "my_data" (
  "real" REAL,
  "double" DOUBLE,
  "integer" INTEGER
);
`);

  await connection.run(
    "INSERT INTO my_data VALUES (30000001, 30000001, 30000001)",
  );

  // QUERY THE TABLE TO VERIFY THE DATA WAS INSERTED CORRECTLY
  const res = await connection.run("Select * from my_data");
  const rows = await res.getRowObjectsJson();

  console.log("stored data:", rows.length, rows[0]);
  // prints: { real: 30000000, double: 30000001, integer: 30000001 }
})();

是否有办法让DuckDB在插入 / 更新时对会导致数据丢失的数值抛出错误?

解决方案

超出取值范围的数值会产生错误:

SELECT CAST(9999 AS TINYINT);
-- Conversion Error:
-- Type INT32 with value 9999 can't be cast because the value is out of range
-- for the destination type INT8

Floating-Point Types 本质上就是不精确的数据类型:

与定点数据类型类似,从字面量转换或从其他数据类型强制转换为浮点类型时,都会将不能被精确表示的输入存储为近似值

在大多数平台上,FLOAT类型的取值范围至少为1E-37到 1E+37,精度至少为6 位十进制数字。 DOUBLE类型通常的取值范围大约为1E-307到 1E+308,精度至少为15位

一般来说:

如果你需要对具有已知小数位数的数字进行精确存储,并且需要对加法、减法和乘法(如货币金额)进行精确运算,请改用DECIMAL数据类型或其NUMERIC别名。

没有溢出:

SELECT CAST(30000001 AS FLOAT);
┌─────────────────────────┐
│ CAST(30000001 AS FLOAT) │
│          float          │
├─────────────────────────┤
│ 30000000.0              │
└─────────────────────────┘

PostgreSQL:

SELECT CAST(30000001 AS FLOAT4);
--float4
--3e+07

db<>fiddle demo

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章