定點小數型別: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 欄位上,更新會更早以400Only 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;要清除選填的decimalcell,請送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中,舊版filtersmap 會先把值正規化到欄位的 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表示的字串。缺少時,decimalavg會收到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;decimalavg需要在欄位定義中提供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成分與 upsertmatch_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"),而decimalcell 一律顯示完整 scale("1354.50")。
動手試試
到 API Playground 用 columns.create 建立 decimal 欄位,再以 records.create 寫入 "1290.5",比較回傳的 "1290.50" 與 float cell 的結果。