Skip to Content
核心概念欄位型別定點小數

定點小數型別:decimal

用途

價格、稅率、帳務金額,以及任何必須精確到固定小數位數的值,都使用 decimal。float 是二進位浮點數,因此 0.1 + 0.2 並不恰好等於 0.3;decimal cell 則保存精確的定點數,過程中絕不會經過二進位浮點數。這個 cell 以 JSON 字串寫入與讀取,並以欄位宣告的 scale 作為小數位數儲存與回傳,例如 "1290.50"。

選用的幣別/計量單位中繼資料與 precision/scale 分開,不執行轉換;既有無單位 decimal schema 仍有效。

建立 schema

decimal 欄位要自行宣告形狀。送出以下 columns.create body:

{ "name": "單價", "type": "decimal", "precision": 12, "scale": 2, "allow_negative": false, "required": true, "default_value": "0.00", "description": "未稅單價" }
  • precision 是有效數字位數的上限,為 1 到 38 的整數;scale 是固定的小數位數,為 0 到 18 與 precision 兩者較小值之間的整數。因此整數部分最多只能用 precision − scale 位:上例的欄位最多容納 10 位整數與恰好 2 位小數。
  • allow_negative 是布林值,決定是否接受負值。
  • 三個欄位在 decimal 欄位上都是必填,而且嚴格檢查型別:precision 與 scale 必須是 JSON 整數、allow_negative 必須是 JSON 布林值。在 columns.create 與 tables.create 上,缺少、型別錯誤或超出範圍的值(包含大於 precision 的 scale)都會收到 422。在其他欄位型別上送出其中任何一項(即使是 null)都會被拒絕,訊息為 precision/scale/allow_negative are only valid on decimal columns:在 columns.create 與建立資料表的欄位清單中是 422,在 columns.update 則是 400(在 link、rollup、lookup 或 formula 欄位上,更新會更早以 400 Only name/description can be updated on <type> columns (got: ...) 拒絕)。
  • default_value 必須是符合宣告的小數字串,並以欄位的 scale 儲存;JSON 數字或不符合宣告的值,在 columns.create 上是 422,在 columns.update 上是 400。
  • max_length、options、附件設定與計算欄設定在 columns.create 上一律以 422 拒絕。required 與 description 的用法和其他純量欄位相同;若表已有 live 紀錄,新增 required 欄位時仍必須提供 default_value。

合法與不合法的值

請寫入純小數字串:可有開頭的 -、沒有前導零的整數部分,以及可選的 . 加上數字。小數位數少於 scale 時會補零,因此下面的 body 會儲存並回傳 "1290.50":

{ "data": { "單價": "1290.5" } }

不符合的寫入會收到 400,訊息類似 Field '單價' must be a valid decimal string: decimal value has more fractional places than scale。以下值會被拒絕:

{ "data": { "單價": 1290.5 } }
  • JSON 數字,例如 1290.5,以及不是純小數的字串:"1,290.50"、"+5"、".5"、"5."、" 5"、"007" 或 "1e3"。
  • 小數位數多於 scale,例如 "1290.505"。寫入絕不會捨入,即使多出的位數全是零也一樣(scale 為 2 時 "1.200" 會失敗),因此請在前端先自行捨入。
  • 整數位數超過 precision − scale。
  • allow_negative 為 false 時的負值,以及任何欄位中的負零,例如 "-0.00"。
  • 空字串 ""。和其他欄位型別不同,這裡的空字串不算空 cell;要清除選填的 decimal cell,請送 null。

顯示與回傳

讀取時回傳以欄位 scale 儲存的字串:"1290.50",零則為 "0.00"。請保留成字串,或用 decimal 函式庫解析。38 位的值放不進 JavaScript number,轉成 number 會重新引入 decimal 原本要避免的捨入誤差。

查詢、排序與彙總

Decimal cell 以數值精確比較,而不是當成文字比較。

  • 篩選。 decimal 欄位的 stored_filters 接受 eq、neq、gt、gte、lt、lte、in、between、is_null 與 is_not_null。每個運算元(包含每個 in 項目與 between 的兩個界線)都是像 "1200.50" 的小數字串,不必寫成欄位的 scale。JSON 數字或空字串會收到 400,訊息為 decimal filter value must be a decimal string;不支援 contains。在 records.search 與 records.export 中,舊版 filters map 會先把值正規化到欄位的 scale,因此 "12.5" 會比對到儲存的 "12.50",不符合宣告的值是 400。套用儲存檢視與公開讀取查詢則把舊版 filters 的值(檢視的;公開讀取時還包括呼叫端的)當成原始字串比較,因此在那裡請寫成欄位的 scale,或改用 stored_filters。
  • 排序。 sort_by 與多欄 sort 會依數值排序 decimal 欄位。
  • 彙總。 records.aggregate 可以用 decimal 欄位 group_by,count 與 count_distinct 的用法和其他儲存欄位相同。sum、min 與 max 回傳以欄位 scale 表示的小數字串。avg 必須在 metric 上同時設定 result_scale(0 到 18)與 rounding_mode(half_even、half_up、down、floor 或 ceiling),並回傳以 result_scale 表示的字串。缺少時,decimal avg 會收到 400(decimal avg requires result_scale and rounding_mode)。只送其中一個是 422(Value error, result_scale and rounding_mode must be supplied together),把它們用在 avg 以外的 metric(Value error, result_scale/rounding_mode require agg=avg)、超出 0 到 18 的 result_scale,或任何其他 rounding_mode 也一樣;對非 decimal 欄位的 avg 同時送兩者則是 400(result_scale/rounding_mode are only valid for decimal avg)。

公式、查找與彙總欄

  • 讀取 decimal 欄位的公式會以精確小數運算求值;請用 DECIMAL、QUANTIZE 與 DIVIDE 轉換、捨入與相除。小數結果以小數字串回傳,比較運算仍回傳布林值。
  • Rollup 可以對 decimal 欄位做 sum、avg、min 或 max;decimal avg 需要在欄位定義中提供 result_scale 與 rounding_mode。
  • Lookup 會顯示儲存的小數字串。

變更 precision、scale 或正負號

columns.update 可以對既有的 decimal 欄位修改 precision、scale 與 allow_negative。後端會先檢查每一個儲存的 cell,包含 live 與已進垃圾桶的紀錄;每個需要新表示法的 cell,都會在同一個 schema transaction 中被精確改寫,每筆被改寫的紀錄各有新的版本與歷史紀錄。至少有一個值被改寫時,回應會帶有 migration_info,訊息為 Decimal configuration updated; migrated N exact record value(s)。

  • 縮小 scale 只能捨去值為零的小數位。只要有一個 cell 放不下,整個變更就會以 400 被拒絕,且不會改寫任何資料。
  • 紀錄超過 10,000 筆(含垃圾桶內的紀錄)的表會以 400 被拒絕(decimal config migration exceeds 10000 records; use an explicit bounded migration before changing this column);這種變更需要另外做資料遷移。
  • 只要表內還有任何紀錄(live 或已進垃圾桶),就會以 400 拒絕把欄位的 type 改成或改離 decimal(decimal type/config changes on a table with records require an explicit data migration,離開 decimal 時則是 decimal type changes on a table with records require an explicit data migration)。請新增欄位再遷移資料。
  • 更新是依合併後的宣告來檢查:scale 大於最後的 precision 是 400(decimal scale must be an integer from 0 to min(18, precision));改成 type: "decimal" 卻漏掉這三個欄位中的任何一個也是 400,訊息會依 precision、scale、allow_negative 的順序指出第一個缺少的欄位(decimal precision must be an integer from 1 to 38、上面的 scale 訊息,或 decimal allow_negative must be a boolean)。只有 JSON 型別錯誤、超出 1 到 38 的 precision 或超出 0 到 18 的 scale,會更早以 422 拒絕。

規則、鍵與匯入

  • decimal 欄位可以當 unique 或 unique_tuple 成分與 upsert match_column,也可以當 IaC record natural key。比對時使用數值,因此 "1.2" 與 "1.20" 是同一個鍵。
  • CSV 與 XLSX 匯入到 decimal 欄位時需要純小數字串。XLSX 必須以 preserve_text_cells=true 擷取,並讓每個對應的來源 cell 保持文字格式:原生數值 cell 可能已被試算表捨入,公式 cell 則是計算結果,因此只要把這兩種 cell 對應到 decimal 欄位,整個匯入請求就會以 400 拒絕。請見檔案匯入。

注意事項

  • 請送出並讀取字串。JSON 數字對 decimal 一律不合法,即使是 1 也一樣。
  • 後端絕不會對寫入做捨入。請在前端先捨入,或把未捨入的金額存進較寬的欄位,再用公式的 QUANTIZE 捨入。
  • -0 與 -0.00 會被拒絕;零請寫成 "0",任何 scale 都接受,並以欄位的 scale 儲存(scale 為 2 時為 "0.00")。"0.00" 只有在 scale 至少為 2 時才會被接受。
  • 公式的計算值和儲存的 cell 形式可能不同:公式回傳沒有尾端零的純小數字串("1354.5"),而 decimal cell 一律顯示完整 scale("1354.50")。

動手試試

到 API Playground 用 columns.create 建立 decimal 欄位,再以 records.create 寫入 "1290.5",比較回傳的 "1290.50" 與 float cell 的結果。

Last updated on